[cfe-commits] r132661 - /cfe/trunk/test/SemaCXX/generalized-initializers.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sun Jun 5 06:48:03 PDT 2011


On 05.06.2011, at 15:03, Johannes Schaub (litb) wrote:

> Sebastian Redl wrote:
> 
>> Author: cornedbee
>> Date: Sun Jun  5 07:23:08 2011
>> New Revision: 132661
>> 
>> URL: http://llvm.org/viewvc/llvm-project?rev=132661&view=rev
>> Log:
>> Expand on braced init list tests.
>> 
> ...
>> namespace objects {
>> 
>> +  template <int N>
>>   struct A {
>> -    A();
>> -    A(int, double);
>> -    A(int, int);
>> -    A(std::initializer_list<int>);
>> -
>> -    int operator[](A);
>> +    A() { static_assert(N == 0, ""); }
>> +    A(int, double) { static_assert(N == 1, ""); }
>> +    A(int, int) { static_assert(N == 2, ""); }
>> +    A(std::initializer_list<int>) { static_assert(N == 3, ""); }
>>   };
>> 
>>   void initialization() {
> ...
>> +    { A<0> a{}; }
>> +    { A<0> a = {}; }
>> +    { A<1> a{1, 1.0}; }
>> +    { A<1> a = {1, 1.0}; }
>> +    { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
>> +    { A<3> a = {1, 2, 3, 4, 5, 6, 7, 8}; }
>> +    { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
>> +    { A<3> a{1, 2}; }
> 
> This looks incorrect to me. All constructs, except the first two (which does 
> value-initialization and use the first constructor), use the last 
> constructor (the initializer list constructor). 

But you can't create a std::initializer_list<int> from the init list {1, 1.0} because there's a narrowing conversion (double -> int) in there.

Hm, the standard isn't clear there IMO, because it doesn't say if the last constructor is viable for the init list {1, 1.0}. 13.3.2p3 requires that there is an implicit conversion sequence.  The special case for initializer lists (since they aren't expressions) is in 13.3.3.5.1p2. There it says that the conversion sequence is the worst sequence required to convert any element of the init list to the std::initializer_list element type. The worst sequence here is the double->int, which is a narrowing conversion and thus not allowed for initializer lists. I believe that this means that the function is not viable, not that this is an error.

Look at this example:

struct A {
  A(std::initializer_list<int>);
  A(std::initializer_list<double>);
};

A a{1, 1.5, 2, 2.5, 3, 3.5 };

I would expect this to work, without me having to rewrite every integer in there with a .0 part attached. However, let's look at it:
the il<double> constructor, for its worst conversion, has the int->double conversion. Since the values converted are constant expressions and round-trip correctly, this is not a narrowing conversion. It is still, however, of Conversion rank.
The il<int> constructor has  the narrowing conversion double->int, which is also of Conversion rank. If this constructor is also viable, the call is ambiguous. I'm not sure if this is a good thing.

But I just realized there's another problem. If narrowing conversions make a call not viable, overload resolution would have to look at the constant-expression-ness and values of the arguments. That might just be unsolvable.

Sebastian





More information about the cfe-commits mailing list