HC4*_*ica 8 c++ templates clang copy-constructor c++11
实例化模板类的特殊成员函数(特别是复制/移动构造函数和复制/移动赋值运算符)是什么时候?一旦类本身被实例化,或者仅在需要它们时?
这出现在以下情况:
template <class T, class U>
struct pair
{
T first;
U second;
pair() : first(), second() {}
pair(const pair&) = default;
};
struct S
{
S() {}
S(const S&) = delete;
S(S&&) = default;
};
int main()
{
pair<int, S> p;
}
Run Code Online (Sandbox Code Playgroud)
Clang拒绝编译此代码,但有以下错误:
test.cpp:9:5: error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be
non-const
pair(const pair&) = default;
^
test.cpp:21:18: note: in instantiation of template class 'pair<int, S>' requested here
pair<int, S> p;
^
Run Code Online (Sandbox Code Playgroud)
建议它在实例化类时立即尝试实例化复制构造函数.
但是,GCC编译代码就好了,这表明它只会在实际需要时尝试实例化复制构造函数.
哪个编译器的行为是正确的?
(赋值算子也有类似的差异.)
更新:这与pair本示例中的复制构造函数已default编辑的事实有关,因为如果我将其定义更改为
pair(const pair& p) : first(p.first), second(p.second) {}
Run Code Online (Sandbox Code Playgroud)
然后代码也传递了clang.
看看当前C++ 11标准的第14.7.1节.引用草案的n3242版本:
类模板特化的隐式实例化会导致类成员函数,成员类,静态数据成员和成员模板的声明的隐式实例化,而不是定义或默认参数的隐式实例化.它会导致成员匿名联合的定义的隐式实例化.除非已显式实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化; 特别是,除非静态数据成员本身以需要静态数据成员的定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用).
因此,这意味着,当您使用类作为上面的类型时,只有声明用它实例化.因此,不应实例化复制构造函数的实际(默认)实现,因为在上面的代码中不需要它.所以GCC正确处理这个问题,而Clang却没有.
您的编辑也表明,Clang过早地为默认复制构造函数生成实现,因为您直接实现的复制构造函数也是错误的(您不能S像在自己的实现中那样调用复制构造函数).由于默认的实现和你的实现在所有方面都应该是相同的(包括实例化的时间),我会认为这是一个铿锵的bug.
标准的相关段落是[dcl.fct.def.default]/1:
显式默认的函数应[...]具有相同的声明函数类型(除了可能不同的引用限定符,并且在复制构造函数或复制赋值运算符的情况下,参数类型可以是“引用非-const
T",其中T是成员函数的类的名称),就好像它已被隐式声明一样
即使从未使用过默认功能,此规则也适用。现在,[class.copy]/9 说:
隐式声明的复制构造函数将具有以下形式
X::X(const X&)如果 [...] 的所有非静态数据成员
X都是类类型M[...],则每个此类类类型都有一个复制构造函数,其第一个参数的类型为const M&或const volatile M&。否则,隐式声明的复制构造函数将具有以下形式
X::X(X&)
因此,这样的示例格式不正确(并且应该生成您所看到的诊断信息):
struct A {
A();
A(A&); // Note, non-const type A in copy constructor
};
template<typename T>
struct B {
T t;
B();
B(const B&) = default;
};
B<A> b; // error, B<A>::B(const B&) is defaulted but has the wrong type
Run Code Online (Sandbox Code Playgroud)
但是,在您的示例中,此规则不适用。由于 clang bug(已修复),已删除的复制构造函数被错误地视为具有非常量参数类型,从而导致此错误。
| 归档时间: |
|
| 查看次数: |
4798 次 |
| 最近记录: |