Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Single value in constructs vs argument list for construction

Tags:

c++

c++11

This question pertains to this code snippet reproduced below:

struct A { 
    A():b(0) { } 
    A(const A&, int b = 0):b(b) { } 
    int b; 
};

int main() {
  A a;

  const A& a1 = { a };  
  const A& a2 = { a, 1 };
  a.b = 2;   
  std::cout << a1.b << a2.b << std::endl;
}

The right hand side of the assignment of a1 can be a single value in constructs or an argument list for construction. Is there anywhere in the standard that specifies which interpretation takes precedence? For a2, it is a construction of a temporary A whose address is assigned to a2, if I did not misunderstand.

BTW, compiling this code by clang++ in Coliru produced output 21. gcc++-4.8 output 01.

like image 577
Candy Chiu Avatar asked Oct 24 '13 19:10

Candy Chiu


2 Answers

The definition of list-initialization has changed quite a bit since the publication of the C++11 Standard due to defect reports.

From draft n3485 (after the Standard has been published, with some corrections but without C++1y features) [dcl.init.list]/3

List-initialization of an object or reference of type T is defined as follows:

  • If T is an aggregate [...]
  • Otherwise, if the initializer list has no elements [...]
  • Otherwise, if T is a specialization of std::initializer_list<E> [...]
  • Otherwise, if T is a class type [...]
  • 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; if a narrowing conversion is required to convert the element to T, the program is ill-formed.
  • 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
  • [...]

In the latest draft from the Committee's github repo (ce016c64dc), only a slight change applies here to one point [dcl.init.list]/3:

  • 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.

From draft n3242 (before the Standard) [dcl.init.list]/3:

List-initialization of an object or reference of type T is defined as follows:

  • If the initializer list has no elements [...]
  • Otherwise, if T is an aggregate [...]
  • Otherwise, if T is a specialization of std::initializer_list<E> [...]
  • Otherwise, if T is a class type [...]
  • Otherwise, if T is a reference to class type or if T is any reference type and the initializer list has no elements, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary.
  • [...]

(I don't have a copy of the Standard itself right now.)


Let's assume your compiler implements the proposed resolutions to the defect reports. Then, the first example

const A& a1 = { a };

initializes like const A& a1 = a; (no temporary); and the second example

const A& a2 = { a, 1 };

initializes like const A& a2 = A(a,1);.

like image 110
dyp Avatar answered Oct 22 '22 17:10

dyp


8.5.4/3 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.

In your example, a1 does not bind directly to a, but to a temporary copy-constructed from a.

like image 43
Igor Tandetnik Avatar answered Oct 22 '22 18:10

Igor Tandetnik