为什么模板化非 const 参数构造函数优于给定的复制构造函数
why templated non const parameter constructor is preferred to given copy constructor
我想让我的 class 能够在 std::variant
中使用。
应该工作的简单代码是:
int main()
{
std::variant< int, A > v;
A a(1);
v = a;
}
我的 class 包含一个模板化构造函数:
template <typename T> A( T& );
这时候麻烦开始了!构造函数绑定到来自 std::variant
的调用,不再使用提供的 A(const A&)
。
出于复制和粘贴的原因,完整示例在此处:
#include <iostream>
#include <variant>
class A
{
private:
int x;
public:
A( A&&) {}
A( const A& ) {}
A(){}
~A() {}
A& operator=( const A& ) { return *this;}
A& operator=( A&& ) {return *this;}
template <typename T>
A( T& t )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
A(int _x):x{_x}{}
};
int main()
{
std::variant< int, A > v;
A a(1);
v = a;
}
背景:
为什么模板在这里?
使用采用序列化程序类型的构造函数时,问题就开始了。序列化器可以有多种类型,取决于要序列化的文件或流。
备注:我知道缺少构造函数的功能!
问题不在于 std::variant
。问题出在构造函数模板上,
template <typename T>
A(T& t)
这样的构造函数是有问题的,因为当参数是 A
类型的非 const
左值时,此构造函数优先于采用 const A&
的复制构造函数---这是通常不是预期的行为。为了防止这种情况,我们通常用 SFINAE 来约束这个构造函数:
template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, A>>>
A(T& t) // or T&& t
并且可能会考虑制作它 explicit
。
我们通常不提供采用非 const
A&
的复制构造函数,因为它们在采用 const A&
.
的复制构造函数旁边是多余的
我想让我的 class 能够在 std::variant
中使用。
应该工作的简单代码是:
int main()
{
std::variant< int, A > v;
A a(1);
v = a;
}
我的 class 包含一个模板化构造函数:
template <typename T> A( T& );
这时候麻烦开始了!构造函数绑定到来自 std::variant
的调用,不再使用提供的 A(const A&)
。
出于复制和粘贴的原因,完整示例在此处:
#include <iostream>
#include <variant>
class A
{
private:
int x;
public:
A( A&&) {}
A( const A& ) {}
A(){}
~A() {}
A& operator=( const A& ) { return *this;}
A& operator=( A&& ) {return *this;}
template <typename T>
A( T& t )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
A(int _x):x{_x}{}
};
int main()
{
std::variant< int, A > v;
A a(1);
v = a;
}
背景:
为什么模板在这里? 使用采用序列化程序类型的构造函数时,问题就开始了。序列化器可以有多种类型,取决于要序列化的文件或流。
备注:我知道缺少构造函数的功能!
问题不在于 std::variant
。问题出在构造函数模板上,
template <typename T>
A(T& t)
这样的构造函数是有问题的,因为当参数是 A
类型的非 const
左值时,此构造函数优先于采用 const A&
的复制构造函数---这是通常不是预期的行为。为了防止这种情况,我们通常用 SFINAE 来约束这个构造函数:
template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, A>>>
A(T& t) // or T&& t
并且可能会考虑制作它 explicit
。
我们通常不提供采用非 const
A&
的复制构造函数,因为它们在采用 const A&
.