Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of const reference member with deleted copy constructor

This code, with a const A& a member in B, where A has a deleted copy constructor, doesn't compile in GCC 4.8.1, but it works OK in clang 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};
}

Which one of the compilers is right?

The error in GCC is:

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

like image 480
smancill Avatar asked Jul 17 '14 03:07

smancill


1 Answers

Your example can be reduced to

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
}

The initialization of ar2 fails on gcc-4.8 with the error

error: use of deleted function ‘A::A(const A&)’

It compiles cleanly on clang3.4 and gcc4.9. This is the result of the resolution to CWG issue 1288.

N3337 contains the following language for list-initialization:

§8.5.4/3 [dcl.init.list]

List-initialization of an object or reference of type T is defined as follows:
...
— Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary

This, of course, means that the initialization of ar2 requires an accessible copy-constructor, hence the error.


The language has changed in N3797, where the initialization from an initializer list containing a single element takes precedence over the case quoted above.

— Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element; ...
— Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is copy-list-initialized or direct-list-initialized, depending on the kind of initialization for the reference, and the reference is bound to that temporary.

So gcc 4.9 and clang 3.4 are implementing the resolution of issue 1288, while gcc 4.8 is following the wording in the C++11 standard.

like image 195
Praetorian Avatar answered Oct 18 '22 03:10

Praetorian