我找不到简短的标题。 :(
假设我有一个简单的C ++ 11模板类定义如下:
#include <utility>
template <typename T>
class A
{
public:
T v;
A(){};
template <typename U>
A(const A<U>& a); // copy ctor
A(A<T>&& a); // move ctor
};
template <typename T>
template <typename U>
A<T>::A(const A<U>& a) // copy ctor
{
v = a.v;
}
template <typename T> // move ctor
A<T>::A(A<T>&& a)
{
v = std::move(a.v); // although moving PODs does not make sense in my example
}
现在,我的 C ++ 11代码使用以上C ++ 11类,如下所示:
int main()
{
A<char> a;
A<float> b(a); // okay
A<char> c(a); // gcc output is as below:
// error: use of deleted function 'constexpr A<char>::A(const A<char>&)'
// note: 'constexpr A<char>::A(const A<char>&)' is implicitly declared
// as deleted because 'A<char>' declares a move constructor or move
// assignment operator
return 0;
}
它提供错误use of deleted function 'constexpr A<char>::A(const A<char>&)'
。
然而,当在类定义中没有使用任何移动语义时,编译并正常运行,如下所示:
#include <utility>
template <typename T>
class A
{
public:
T v;
A(){};
template <typename U>
A(const A<U>& a);
// A(A<T>&& a); // removed move ctor
};
template <typename T>
template <typename U>
A<T>::A(const A<U>& a)
{
v = a.v;
}
我的问题是:
为什么gcc编译器在两种情况下以不同方式处理 copy ctor 中的template <typename U>
?
为什么在存在移动ctor 时无法处理类型名称 T == U
?
为什么需要明确写入另一个模板
使用时功能template <typename T> A<T>::A(const A<U>& a)
移动ctor ?
答案 0 :(得分:4)
您还没有写过复制构造函数。来自C ++ 11标准中的{{1}}:
X类的非模板构造函数是一个复制构造函数,如果它的第一个参数是X&amp;类型,const X&amp;,volatile X&amp;或const volatile X&amp;,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6)。
(我看不到将模板构造函数称为复制构造函数的规定)
因此
如果类定义没有显式声明复制构造函数,则会隐式声明一个
两个示例之间的区别在于您是否有移动构造函数:
如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除;否则,它被定义为默认(8.4)
答案 1 :(得分:1)
定义移动构造函数禁用了复制构造函数。你想要的是转换构造函数,顾名思义,它将其参数转换为类的类型。如果您的复制/移动构造函数没有做任何特殊操作,请忽略或default
它们。为了解释您最后的混淆,您可以在假拷贝构造函数中省略模板参数的原因是因为注入的类名。这意味着无论您在哪里看到A
,它都会默默地替换A<T>
。为了清楚起见,我把它包括在内。
template <typename T>
class A
{
public:
T v;
A() = default;
template <typename U>
A<T>(const A<U>& a);
A(const A<T>& a) = default;
A(A<T>&& a) = default;
};