开发者

How to use enable_if to enable member functions based on template parameter of class

In code:

template<class T>
struct is_builtin
{
    enum {value = 0};
};

template<>
struct is_builtin<char>
{
    enum {value = 1};
};

template<>
struct is_builtin<int>
{
    enum {value = 1};
};

template<>
struct is_builtin<double>
{
    enum {value = 1};
};

template<class T>
struct My
{
    typename enable_if<is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Built-in as a param.\n";
    }


    typename enable_if<!is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Non - built-in as a param.\n";
    }
};

struct A
{
};

int main()
{
    A a;
    My<int> m;
    My<A> ma;
    m.f(1);
    ma.f(a);
    return 0;
}

I'm getting an error:

error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type&开发者_C百科gt;'    

Obviously I don't understand how to use enable_if. What I was thinking was that I can enable one or the second one member function from a set of member functions during compilation time but it does not work. Could anyone please explain to me how to do it correctly?

Edited

What I really can't understand is why isn't there typedef in one of those def. Compiler cannot find it and it wont compile it.


You can't use class template parameters to get SFINAE for member functions.

You either need to

  • make the member function a member function template instead and use enable_if on the member function template's template parameters or

  • move the member function f into a policy class and specialize the class template using enable_if.


Here's how it works (note that for convenience I replaced your is_builtin trait with std::is_arithmetic and used further C++11 stuff, but it works any way):

template<class T>
struct My
{
    template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr>
    void f(T_ arg)
    {
        std::cout << "Built-in as a param.\n";
    }

    template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr>
    void f(T_ arg)
    {
        std::cout << "Non - built-in as a param.\n";
    }
};

DEMO

The crucial part is to bring the template parameter into the immediate context by using a default function template parameter T_ which equals the class template parameter T. For more details, see this question.


You can fix your code by using modified enable_if

template < typename T >
struct __Conflict {};

template <bool B, class T = void>
struct __enable_if { typedef __Conflict<T> type; };

template <class T>
struct __enable_if<true, T> { typedef T type; };

Example of usage:

template <typename T>
class Lazy
{
public:
    void _ctor(bool b);
    void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type);
};

template <typename T>
void Lazy<T>::_ctor(bool b)
{
    std::cout << "bool " << b << std::endl;
};

template <typename T>
void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t)
{
    std::cout << "T " << t << std::endl;
};

int main(int argc, char **argv)
{
    Lazy<int> i;
    i._ctor(10);
    i._ctor(true);

    Lazy<bool> b;
    b._ctor(true);

    return 0;
}


enable_if expects a metafunction. To use a bool you need enable_if_c. I'm surprised you're not getting errors explaining THAT problem.

You can fix your metafunction by declaring a 'type' typedef inside that is simply itself. Then you can use boost::enable_if<is_builtin<T>>::type

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜