为什么 C++11 无法在模板 class 的构造函数中处理两个模板类型名称 T == U?
Why does C++11 fail to treat two template typenames T == U in constructor in a template class?
I could not find a short and better title. :(
假设我有一个简单的C++11模板class定义如下:
#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 class 如下:
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>&)'
。
但是,当我没有在class定义中使用任何移动语义时,它可以正常编译和运行,如下所示:
#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>
?
为什么 无法处理类型名称 T == U
移动构造函数的存在?
为什么我还需要显式编写另一个模板
使用时函数 template <typename T> A<T>::A(const A<U>& a)
移动构造函数?
你还没有写拷贝构造函数。来自 C++11 标准中的 [class.copy]
:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).
(我没有看到将 模板 构造函数称为复制构造函数的规定)
因此
If the class definition does not explicitly declare a copy constructor, one is declared implicitly
两个例子的区别在于你有没有移动构造函数:
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4)
定义移动构造函数禁用了复制构造函数。您想要的是一个 转换构造函数 ,顾名思义,它将其参数转换为 class 的类型。如果您的 copy/move 构造函数没有做任何特殊的事情,则忽略或 default
它们。为了解释你最后的困惑,你可以在你的假复制构造函数中省略模板参数的原因是因为 注入的 class 名称 。这意味着无论您在哪里看到 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;
};
I could not find a short and better title. :(
假设我有一个简单的C++11模板class定义如下:
#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 class 如下:
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>&)'
。
但是,当我没有在class定义中使用任何移动语义时,它可以正常编译和运行,如下所示:
#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>
?为什么 无法处理类型名称
T == U
移动构造函数的存在?为什么我还需要显式编写另一个模板 使用时函数
template <typename T> A<T>::A(const A<U>& a)
移动构造函数?
你还没有写拷贝构造函数。来自 C++11 标准中的 [class.copy]
:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).
(我没有看到将 模板 构造函数称为复制构造函数的规定)
因此
If the class definition does not explicitly declare a copy constructor, one is declared implicitly
两个例子的区别在于你有没有移动构造函数:
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4)
定义移动构造函数禁用了复制构造函数。您想要的是一个 转换构造函数 ,顾名思义,它将其参数转换为 class 的类型。如果您的 copy/move 构造函数没有做任何特殊的事情,则忽略或 default
它们。为了解释你最后的困惑,你可以在你的假复制构造函数中省略模板参数的原因是因为 注入的 class 名称 。这意味着无论您在哪里看到 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;
};