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


_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to