此代码在const A& a
中有B
成员,其中A
有一个已删除的复制构造函数,在GCC 4.8.1中无法编译,但它可以正常运行铿锵声3.4:
class A {
public:
A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
};
class B{
public:
B(const A& a)
: a{a}
{ }
private:
const A& a;
};
int main()
{
A a{};
B b{a};
}
哪一个编译器是对的?
GCC中的错误是:
prog.cpp: In constructor ‘B::B(const A&)’:
prog.cpp:11:14: error: use of deleted function ‘A::A(const A&)’
: a{a}
^
prog.cpp:4:5: error: declared here
A(const A&) = delete;
^
Ideone:http://ideone.com/x1CVwx
答案 0 :(得分:9)
您的示例可以缩减为
class A {
public:
A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
};
int main()
{
A a{};
A const& ar1(a);
A const& ar2{a}; // fails on gcc 4.8
}
ar2
的初始化在gcc-4.8上失败,错误为
error: use of deleted function ‘A::A(const A&)’
它在clang3.4和gcc4.9上完全编译。这是对CWG issue 1288的解决方案的结果。
N3337包含 list-initialization 的以下语言:
§8.5.4/ 3 [dcl.init.list]
类型
T
的对象或引用的列表初始化定义如下:
-...
- 否则,如果T
是引用类型,则为引用类型的prvalue临时值T
是列表初始化的,引用绑定到该临时
这当然意味着ar2
的初始化需要一个可访问的拷贝构造函数,因此错误。
N3797中的语言发生了变化,其中包含单个元素的初始化列表的初始化优先于上面引用的情况。
- 否则,如果初始化列表具有类型为
E
的单个元素且T
不是引用类型或其引用类型与E
引用相关,则该对象或引用从该元素初始化;...
- 否则,如果T
是引用类型,则T
引用的类型的prvalue临时值是copy-list-initialized或direct-list-initialized,具体取决于引用的初始化类型,并且引用绑定到那个临时的。
所以gcc 4.9和clang 3.4正在实现问题1288的解决方案,而gcc 4.8遵循C ++ 11标准中的措辞。