使用已删除的复制构造函数初始化const引用成员

时间:2014-07-17 03:48:50

标签: c++ c++11 reference uniform-initialization

此代码在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

1 个答案:

答案 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标准中的措辞。