使用 enable_if 禁用模板 class 的模板构造函数
Using enable_if to disable a template constructor of a template class
当模板构造函数的参数类型与类型“MyClass
”匹配时,我正在尝试使用 std::enable_if
禁用模板 class 的模板构造函数,以便我可以使用我的其他构造函数,它允许我用另一个模板的 class 初始化当前模板的 class。
template <typename t, size_t size>
class MyClass
{
public:
MyClass() { data.fill(static_cast<T>(0)); }
template <typename... Args> // i want to disable this if Args = MyClass
MyClass(Args&&... args) : data{ std::forward<Args>(args)... } {}
template <size_t size2>
MyClass(const Myclass<t, size2>& other_sized_template) { /*do stuff*/ } // this won't work unless the template ctor above is disabled if the arguments passed are of type Myclass
private:
std::array<t, size> data;
};
首先你需要一个助手来判断 Args...
是否是单个 MyClass<T, N>
:
#include <cstddef>
#include <type_traits>
template <class, size_t>
class MyClass;
template <class T>
struct IsMyClass {
template <size_t Size>
static std::true_type test(const MyClass<T, Size>&);
static std::false_type test(...);
template <class V, class... Further>
static constexpr bool value = (
(sizeof...(Further) == 0) &&
decltype(test(std::declval<V>()))::value
);
};
你可以像这样使用它
IsMyClass<int>::template value<Args...>
测试 Args...
是否为 MyClass<int, Some_Int>
。现在使用这个助手:
#include <cstdio>
template <typename T, size_t Size>
class MyClass
{
public:
MyClass() {
printf("Default constructor\n");
}
template <
class ...Args,
class Check = std::enable_if_t<(!IsMyClass<T>::template value<Args...>)>
>
MyClass(Args&&... args) {
printf("Args != MyClass\n");
}
template <size_t Size2>
MyClass(const MyClass<T, Size2>& other_sized_template) {
printf("other_sized_template\n");
}
};
一个简单的测试是否有效:
int main() {
printf("init\n");
MyClass<int, 10> myclass_int10;
MyClass<void, 10> myclass_void10;
printf("1+2\n");
MyClass<int, 20> test1(myclass_int10);
MyClass<int, 20> test2(myclass_void10);
printf("3+4\n");
MyClass<void, 20> test3(myclass_int10);
MyClass<void, 20> test4(myclass_void10);
printf("5+6\n");
MyClass<int, 20> test5(myclass_int10, myclass_int10);
MyClass<int, 20> test6(myclass_void10, myclass_void10);
return 0;
}
确实如此:
$ g++ -std=c++14 ./x.cpp
$ ./a.out
init
Default constructor
Default constructor
1+2
other_sized_template
Args != MyClass
3+4
Args != MyClass
other_sized_template
5+6
Args != MyClass
Args != MyClass
我能想象的最好的就是定义一个类型特征,比如 notOnlyOneMyClass
template <typename ...>
struct notOnlyOneMyClass
{ using type = void; };
template <typename T, std::size_t S>
struct notOnlyOneMyClass<T, MyClass<T, S>>
{ };
接收一个类型列表并定义一个 type
,除非只接收两种类型,而第二个是 MyClass
,其类型对应于第一个。
现在SFINAE的使用很简单
template <typename... Args,
typename notOnlyOneMyClass<T,
typename std::decay<Args>::type...>::type * = nullptr>
MyClass (Args && ... args) : data{ { std::forward<Args>(args)... } }
{ }
以下是完整的工作示例
#include <array>
template <typename, std::size_t>
class MyClass;
template <typename ...>
struct notOnlyOneMyClass
{ using type = void; };
template <typename T, std::size_t S>
struct notOnlyOneMyClass<T, MyClass<T, S>>
{ };
template <typename T, std::size_t S>
class MyClass
{
public:
MyClass()
{ data.fill(static_cast<T>(0)); }
template <typename... Args,
typename notOnlyOneMyClass<T,
typename std::decay<Args>::type...>::type * = nullptr>
MyClass (Args && ... args) : data{ { std::forward<Args>(args)... } }
{ }
template <std::size_t S2>
MyClass (MyClass<T, S2> const & ost)
{ }
private:
std::array<T, S> data;
};
int main ()
{
MyClass<int, 1U> mi1;
MyClass<int, 2U> mi2{1, 2};
MyClass<int, 3U> mi3{mi1};
MyClass<int, 4U> mi4{std::move(mi2)};
MyClass<int, 5U> mi5{MyClass<int, 6U>{}};
// MyClass<int, 6U> mi6{MyClass<long, 7U>{}}; // error! int != long
}
您可以检查该类型是否是 MyClass
的实例化 class 具有部分特化的模板。例如
template<class...>
struct is_MyClass : std::false_type {};
template <typename T, size_t size>
struct is_MyClass<MyClass<T, size>> : std::true_type {};
然后像
那样禁用构造函数
template <typename... Args,
typename = std::enable_if_t<
!is_MyClass<
std::remove_cv_t<
std::remove_reference_t<Args>>...>::value> > // i want to disable this if Args = MyClass
MyClass(Args&&... args) : data{ std::forward<Args>(args)... } {}
当模板构造函数的参数类型与类型“MyClass
”匹配时,我正在尝试使用 std::enable_if
禁用模板 class 的模板构造函数,以便我可以使用我的其他构造函数,它允许我用另一个模板的 class 初始化当前模板的 class。
template <typename t, size_t size>
class MyClass
{
public:
MyClass() { data.fill(static_cast<T>(0)); }
template <typename... Args> // i want to disable this if Args = MyClass
MyClass(Args&&... args) : data{ std::forward<Args>(args)... } {}
template <size_t size2>
MyClass(const Myclass<t, size2>& other_sized_template) { /*do stuff*/ } // this won't work unless the template ctor above is disabled if the arguments passed are of type Myclass
private:
std::array<t, size> data;
};
首先你需要一个助手来判断 Args...
是否是单个 MyClass<T, N>
:
#include <cstddef>
#include <type_traits>
template <class, size_t>
class MyClass;
template <class T>
struct IsMyClass {
template <size_t Size>
static std::true_type test(const MyClass<T, Size>&);
static std::false_type test(...);
template <class V, class... Further>
static constexpr bool value = (
(sizeof...(Further) == 0) &&
decltype(test(std::declval<V>()))::value
);
};
你可以像这样使用它
IsMyClass<int>::template value<Args...>
测试 Args...
是否为 MyClass<int, Some_Int>
。现在使用这个助手:
#include <cstdio>
template <typename T, size_t Size>
class MyClass
{
public:
MyClass() {
printf("Default constructor\n");
}
template <
class ...Args,
class Check = std::enable_if_t<(!IsMyClass<T>::template value<Args...>)>
>
MyClass(Args&&... args) {
printf("Args != MyClass\n");
}
template <size_t Size2>
MyClass(const MyClass<T, Size2>& other_sized_template) {
printf("other_sized_template\n");
}
};
一个简单的测试是否有效:
int main() {
printf("init\n");
MyClass<int, 10> myclass_int10;
MyClass<void, 10> myclass_void10;
printf("1+2\n");
MyClass<int, 20> test1(myclass_int10);
MyClass<int, 20> test2(myclass_void10);
printf("3+4\n");
MyClass<void, 20> test3(myclass_int10);
MyClass<void, 20> test4(myclass_void10);
printf("5+6\n");
MyClass<int, 20> test5(myclass_int10, myclass_int10);
MyClass<int, 20> test6(myclass_void10, myclass_void10);
return 0;
}
确实如此:
$ g++ -std=c++14 ./x.cpp
$ ./a.out
init
Default constructor
Default constructor
1+2
other_sized_template
Args != MyClass
3+4
Args != MyClass
other_sized_template
5+6
Args != MyClass
Args != MyClass
我能想象的最好的就是定义一个类型特征,比如 notOnlyOneMyClass
template <typename ...>
struct notOnlyOneMyClass
{ using type = void; };
template <typename T, std::size_t S>
struct notOnlyOneMyClass<T, MyClass<T, S>>
{ };
接收一个类型列表并定义一个 type
,除非只接收两种类型,而第二个是 MyClass
,其类型对应于第一个。
现在SFINAE的使用很简单
template <typename... Args,
typename notOnlyOneMyClass<T,
typename std::decay<Args>::type...>::type * = nullptr>
MyClass (Args && ... args) : data{ { std::forward<Args>(args)... } }
{ }
以下是完整的工作示例
#include <array>
template <typename, std::size_t>
class MyClass;
template <typename ...>
struct notOnlyOneMyClass
{ using type = void; };
template <typename T, std::size_t S>
struct notOnlyOneMyClass<T, MyClass<T, S>>
{ };
template <typename T, std::size_t S>
class MyClass
{
public:
MyClass()
{ data.fill(static_cast<T>(0)); }
template <typename... Args,
typename notOnlyOneMyClass<T,
typename std::decay<Args>::type...>::type * = nullptr>
MyClass (Args && ... args) : data{ { std::forward<Args>(args)... } }
{ }
template <std::size_t S2>
MyClass (MyClass<T, S2> const & ost)
{ }
private:
std::array<T, S> data;
};
int main ()
{
MyClass<int, 1U> mi1;
MyClass<int, 2U> mi2{1, 2};
MyClass<int, 3U> mi3{mi1};
MyClass<int, 4U> mi4{std::move(mi2)};
MyClass<int, 5U> mi5{MyClass<int, 6U>{}};
// MyClass<int, 6U> mi6{MyClass<long, 7U>{}}; // error! int != long
}
您可以检查该类型是否是 MyClass
的实例化 class 具有部分特化的模板。例如
template<class...>
struct is_MyClass : std::false_type {};
template <typename T, size_t size>
struct is_MyClass<MyClass<T, size>> : std::true_type {};
然后像
那样禁用构造函数template <typename... Args,
typename = std::enable_if_t<
!is_MyClass<
std::remove_cv_t<
std::remove_reference_t<Args>>...>::value> > // i want to disable this if Args = MyClass
MyClass(Args&&... args) : data{ std::forward<Args>(args)... } {}