当模板构造函数的参数类型与#34; std::enable_if
"类型匹配时,我尝试使用MyClass
禁用模板类的模板构造函数。这样我就可以使用我的其他构造函数,它允许我用另一个类初始化当前模板的类。
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;
};
答案 0 :(得分:4)
您可以通过具有部分特化的类模板检查该类型是否为MyClass
的实例化。 e.g。
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)... } {}
答案 1 :(得分:1)
首先,您需要帮助程序才能判断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
答案 2 :(得分:1)
我能想象的最好的是定义类型特征,比如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
}