Select 在模板参数中通过 SFINAE 构造函数
Select constructor through SFINAE in template arguments
我正在尝试通过 SFINAE select 构造函数,如下所示:
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) { }
};
但编译器报错如下:
error C2535: 'MyClass::MyClass(C)': member function already defined or declared
甚至没有实例化构造函数。
我想出了一个可行但丑陋的解决方案,但由于额外的未使用参数,我不想使用它:
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) { }
};
这里给出了一个简短的用法示例:
void* ptr = nullptr;
MyClass<int> mc1(ptr);
std::vector<int> vec;
MyClass<int> mc2(vec);
// Shall raise an error
// MyClass<int> mc2(0);
特征std::is_pointer
和std::is_class
只是一个例子,原来的特征比较复杂。
有没有办法通过 SFINAE select 构造函数而不向构造函数添加另一个参数(可能非常接近第一个方法)?
再添加一个(虚拟)类型模板参数:
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) { }
问题是参数的默认值不是模板方法签名的一部分。所以你有两个 template<class C,class>ctor(c)
相同的 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) { }
};
这里我们使用依赖类型的模板值参数。它们从不冲突,因为指针模板参数的类型取决于类型参数。
这可能更简单:
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*) { }
};
并非所有这些都需要 std::enable_if_t
完成。
我正在尝试通过 SFINAE select 构造函数,如下所示:
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) { }
};
但编译器报错如下:
error C2535: 'MyClass::MyClass(C)': member function already defined or declared
甚至没有实例化构造函数。
我想出了一个可行但丑陋的解决方案,但由于额外的未使用参数,我不想使用它:
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) { }
};
这里给出了一个简短的用法示例:
void* ptr = nullptr;
MyClass<int> mc1(ptr);
std::vector<int> vec;
MyClass<int> mc2(vec);
// Shall raise an error
// MyClass<int> mc2(0);
特征std::is_pointer
和std::is_class
只是一个例子,原来的特征比较复杂。
有没有办法通过 SFINAE select 构造函数而不向构造函数添加另一个参数(可能非常接近第一个方法)?
再添加一个(虚拟)类型模板参数:
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) { }
问题是参数的默认值不是模板方法签名的一部分。所以你有两个 template<class C,class>ctor(c)
相同的 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) { }
};
这里我们使用依赖类型的模板值参数。它们从不冲突,因为指针模板参数的类型取决于类型参数。
这可能更简单:
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*) { }
};
并非所有这些都需要 std::enable_if_t
完成。