SFINAE 不适用于复制构造函数
SFINAE does not work for copy constructors
我有一个模板class,我想有两个副本。一种用于普通类型,另一种用于非普通类型。
以下代码有效(使用一个副本 ctor):
template <typename T>
struct MyStruct
{
MyStruct()
{}
MyStruct(const MyStruct& o)
{
std::cout << "copy ";
foo(o);
}
template <typename U = T, typename std::enable_if_t<!std::is_trivial<U>::value, int> =0>
void foo(const MyStruct& o)
{
std::cout << "Non trivial" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_trivial<U>::value, int> =0>
void foo(const MyStruct& o)
{
std::cout << "Trivial" << std::endl;
}
MyStruct(MyStruct&& o)
{
std::cout << "Move" << std::endl;
}
};
struct MyType
{
MyType(int i){}
};
int main()
{
MyStruct<int> my1;
MyStruct<int> my2(my1);
MyStruct<MyType> mytype1;
MyStruct<MyType> mytype2(mytype1);
}
// prints
// Copy Trivial
// Copy Non trivial
当我尝试对两个复制 ctors 执行相同操作时,似乎生成了 none 个(均已被 SFINAEd 删除)
struct MyStruct
{
MyStruct()
{}
template <typename U = T, typename std::enable_if_t<!std::is_trivial<U>::value, int> =0>
MyStruct(const MyStruct& o)
{
std::cout << "Non trivial" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o)
{
std::cout << "Trivial" << std::endl;
}
MyStruct(MyStruct&& o)
{
std::cout << "Move" << std::endl;
}
};
代码无法编译:
main.cpp: In function ‘int main()’:
main.cpp:36:26: error: use of deleted function ‘constexpr MyStruct::MyStruct(const MyStruct&)’
MyStruct<int> my2(my1);
^
main.cpp:5:9: note: ‘constexpr MyStruct::MyStruct(const MyStruct&)’ is implicitly declared as deleted because ‘MyStruct’ declares a move constructor or move assignment operator
struct MyStruct
^~~~~~~~
main.cpp:39:37: error: use of deleted function ‘constexpr MyStruct::MyStruct(const MyStruct&)’
MyStruct<MyType> mytype2(mytype1);
^
main.cpp:5:9: note: ‘constexpr MyStruct::MyStruct(const MyStruct&)’ is implicitly declared as deleted because ‘MyStruct’ declares a move constructor or move assignment operator
struct MyStruct
^~~~~~~~
我试过 google 它,我认为 SFINAE 也应该使用复制构造函数。
请不要建议使用if constexpt
或 requires concept
,这个问题是关于SFINAE的。
感谢您的帮助!
遗憾的是,模板构造函数不能是默认、复制或移动构造函数。
MyStruct
的拷贝构造函数的签名如下
MyStruct (MyStruct const &);
在你的第二个例子中,这个函数被隐式删除,因为你写了一个显式移动构造函数。
您的模板构造函数,具有以下签名,
template <typename, int>
MyStruct (MyStruct const &);
是(是)一个有效的构造函数,但是,给定的是一个模板构造函数,(不幸的是删除)真实的复制构造函数是首选。
可能的解决方案:添加一个真正的复制构造函数,通过附加参数调用(委托构造函数)模板构造函数。
我是说
template <typename T>
struct MyStruct
{
MyStruct()
{}
// delegating real copy constructor added
MyStruct(const MyStruct & ms0) : MyStruct{ms0, 0}
{ }
template <typename U = T,
std::enable_if_t<!std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o, int = 0) // <-- added an int argument
{ std::cout << "Non trivial" << std::endl; }
template <typename U = T,
std::enable_if_t<std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o, int = 0) // <-- added and int argument
{ std::cout << "Trivial" << std::endl; }
MyStruct(MyStruct&& o)
{ std::cout << "Move" << std::endl; }
};
我有一个模板class,我想有两个副本。一种用于普通类型,另一种用于非普通类型。 以下代码有效(使用一个副本 ctor):
template <typename T>
struct MyStruct
{
MyStruct()
{}
MyStruct(const MyStruct& o)
{
std::cout << "copy ";
foo(o);
}
template <typename U = T, typename std::enable_if_t<!std::is_trivial<U>::value, int> =0>
void foo(const MyStruct& o)
{
std::cout << "Non trivial" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_trivial<U>::value, int> =0>
void foo(const MyStruct& o)
{
std::cout << "Trivial" << std::endl;
}
MyStruct(MyStruct&& o)
{
std::cout << "Move" << std::endl;
}
};
struct MyType
{
MyType(int i){}
};
int main()
{
MyStruct<int> my1;
MyStruct<int> my2(my1);
MyStruct<MyType> mytype1;
MyStruct<MyType> mytype2(mytype1);
}
// prints
// Copy Trivial
// Copy Non trivial
当我尝试对两个复制 ctors 执行相同操作时,似乎生成了 none 个(均已被 SFINAEd 删除)
struct MyStruct
{
MyStruct()
{}
template <typename U = T, typename std::enable_if_t<!std::is_trivial<U>::value, int> =0>
MyStruct(const MyStruct& o)
{
std::cout << "Non trivial" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o)
{
std::cout << "Trivial" << std::endl;
}
MyStruct(MyStruct&& o)
{
std::cout << "Move" << std::endl;
}
};
代码无法编译:
main.cpp: In function ‘int main()’:
main.cpp:36:26: error: use of deleted function ‘constexpr MyStruct::MyStruct(const MyStruct&)’
MyStruct<int> my2(my1);
^
main.cpp:5:9: note: ‘constexpr MyStruct::MyStruct(const MyStruct&)’ is implicitly declared as deleted because ‘MyStruct’ declares a move constructor or move assignment operator
struct MyStruct
^~~~~~~~
main.cpp:39:37: error: use of deleted function ‘constexpr MyStruct::MyStruct(const MyStruct&)’
MyStruct<MyType> mytype2(mytype1);
^
main.cpp:5:9: note: ‘constexpr MyStruct::MyStruct(const MyStruct&)’ is implicitly declared as deleted because ‘MyStruct’ declares a move constructor or move assignment operator
struct MyStruct
^~~~~~~~
我试过 google 它,我认为 SFINAE 也应该使用复制构造函数。
请不要建议使用if constexpt
或 requires concept
,这个问题是关于SFINAE的。
感谢您的帮助!
遗憾的是,模板构造函数不能是默认、复制或移动构造函数。
MyStruct
的拷贝构造函数的签名如下
MyStruct (MyStruct const &);
在你的第二个例子中,这个函数被隐式删除,因为你写了一个显式移动构造函数。
您的模板构造函数,具有以下签名,
template <typename, int>
MyStruct (MyStruct const &);
是(是)一个有效的构造函数,但是,给定的是一个模板构造函数,(不幸的是删除)真实的复制构造函数是首选。
可能的解决方案:添加一个真正的复制构造函数,通过附加参数调用(委托构造函数)模板构造函数。
我是说
template <typename T>
struct MyStruct
{
MyStruct()
{}
// delegating real copy constructor added
MyStruct(const MyStruct & ms0) : MyStruct{ms0, 0}
{ }
template <typename U = T,
std::enable_if_t<!std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o, int = 0) // <-- added an int argument
{ std::cout << "Non trivial" << std::endl; }
template <typename U = T,
std::enable_if_t<std::is_trivial<U>::value, int> = 0>
MyStruct(const MyStruct& o, int = 0) // <-- added and int argument
{ std::cout << "Trivial" << std::endl; }
MyStruct(MyStruct&& o)
{ std::cout << "Move" << std::endl; }
};