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.
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
.
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;
}
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";
}
};
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 .
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.