mercredi 17 août 2016

list initialization of aggregates: when can it invoke copy constructor?

Consider the following code:

struct A {
  int x;
};

int main() {
  A a;
  A b{a};
}

Is this program well-formed at C++11 standard? In my copy of N3797 it says

8.5.4 List initialization [dcl.init.list]

3: List-initialization of an object or reference of type T is defined as follows:
- If T is an aggregate, aggregate initialization is performed (8.5.1).
- Otherwise, if T is a specialization of std::initializer_list<E>, ...
- Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen using overload resolution. If a narrowing conversion is required to convert any of the types, the program is ill-formed.
- Otherwise, if the initializer list has a single element of type E and either T is not a reference type or it 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 pr-value temporary of the type reference 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.
- Otherwise, if the initializer list has no elements, the object is value-initialized.
- Otherwise, the program is ill-formed.

The point of the example is, the type is an aggregate, but list-initialization is supposed to invoke the copy constructor. On gcc 4.8 and gcc 4.9, at C++11 standard, it fails:

main.cpp: In function ‘int main()’:
main.cpp:7:8: error: cannot convert ‘A’ to ‘int’ in initialization
   A b{a};
        ^

and says A is not convertible to int or similar, because aggregate initialization fails. On gcc 5.4, it works fine at C++11 standard.

On clang you get similar errors with clang-3.5, 3.6, and it starts working at clang-3.7.

I understand that it is well-formed at C++14 standard, and that it was mentioned in a defect report here.

However, what I don't understand is why this was considered a defect in the standard.

When the standard writes,

"If X, foo-initialization is performed. Otherwise, if Y, bar-initialization is performed, .... Otherwise, the program is ill-formed.",

doesn't this mean that if X holds, but foo-initialization cannot be performed, then we should check if Y holds, and then attempt bar-initialization?

This would make the example work, because when aggregate initialization fails, we don't match std::initializer_list, and the next condition we match is "T is a class type", and then we consider constructors.

Note that this does seem to be how it works in this modified example

struct A {
  int x;
};

int main() {
  A a;
  const A & ref;
  A b{ref};
}

All the same compilers treat this the same way as the earlier example, at C++11 and C++14 standards. But it seems that the modified wording from the CWG defect record doesn't apply to this case. It reads:

If T is a class type and the initializer list has a single element of type cv T or a class type derived from T, the object is initialized from that element.

http://ift.tt/2bdAx3l

But in the second code example, the initializer list technically contains const T &. So I don't see how it would work unless after aggregate initialization fails, we are supposed to attempt constructors.

Am I wrong? Is it not supposed to attempt constructors after aggregate initialization fails?

Here's a related example:

#include <iostream>

struct B {
  int x;

  operator int() const { return 2; }
};

int main() {
  B b{1};
  B c{b};
  std::cout << c.x << std::endl;
}

In clang-3.6, gcc-4.8, gcc-4.9, it prints 2, and in clang-3.7, gcc-5.0 it prints 1.

Assuming I'm wrong, and at C++11 standard, list initialization of an aggregate is supposed to be aggregate initialization and nothing else, until the new wording in the defect report is introduced, is it a bug that this happens even when I select -std=c++11 on the newer compilers?

Aucun commentaire:

Enregistrer un commentaire