问题
I'm trying to select a constructor through SFINAE as following:
template<typename T>
class MyClass
{
public:
template<typename C, typename = std::enable_if_t<std::is_class<C>::value>>
MyClass(C) { }
template<typename C, typename = std::enable_if_t<std::is_pointer<C>::value>>
MyClass(C) { }
};
but the compiler complains with following error:
error C2535: 'MyClass::MyClass(C)': member function already defined or declared
without even instantiating the constructor.
I worked out a working but ugly solution which i don't want to use because of the extra unused parameter:
template<typename T>
class MyWorkingClass
{
public:
template<typename C>
MyWorkingClass(C, std::enable_if_t<std::is_class<C>::value>* = nullptr) { }
template<typename C>
MyWorkingClass(C, std::enable_if_t<std::is_pointer<C>::value>* = nullptr) { }
};
A short usage example is given here:
void* ptr = nullptr;
MyClass<int> mc1(ptr);
std::vector<int> vec;
MyClass<int> mc2(vec);
// Shall raise an error
// MyClass<int> mc2(0);
The traits std::is_pointer
and std::is_class
are just an example, the original traits are more complicated.
Is there a way to select the constructor through SFINAE without adding another parameter to the constructor (maybe very close to the first appproach)?
回答1:
The problem is that the default values of arguments are not part of the template method signature. So you have two template<class C,class>ctor(c)
identical ctors.
template<class T>
struct MyClass {
template<class C,
std::enable_if_t<std::is_class<C>{}>* =nullptr
>
MyClass(C) { }
template<class C,
std::enable_if_t<std::is_pointer<C>{}>* =nullptr
>
MyClass(C) { }
};
here we use template value arguments of dependant type. They never conflict, as the type of the pointer template argument is dependant on the type argument.
回答2:
Add one more (dummy) type template parameter:
template <typename C
, typename = std::enable_if_t<std::is_class<C>::value>>
MyClass(C) { }
template <typename C
, typename = std::enable_if_t<std::is_pointer<C>::value>
, typename = void>
// ~~~~~~~~~~~~~~^
MyClass(C) { }
DEMO
回答3:
This may be simplier:
template<typename T>
class MyClass {
public:
template<typename C, typename = std::enable_if_t<std::is_class<C>::value>>
MyClass(C) { }
template<typename C>
MyClass(C*) { }
};
Not all of them need to be done by std::enable_if_t
.
来源:https://stackoverflow.com/questions/32167213/select-constructor-through-sfinae-in-template-arguments