问题
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>'
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.
回答1:
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 ormove the member function
f
into a policy class and specialize the class template usingenable_if
.
回答2:
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;
}
回答3:
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.
回答4:
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
来源:https://stackoverflow.com/questions/4158727/how-to-use-enable-if-to-enable-member-functions-based-on-template-parameter-of-c