Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Direct list initialization compiles successfully, but normal direct initialization fails, why?

For example, code like this:

struct A { A(int); };
struct B { B(A);   };

int main()
{
    B b{{0}}; // OK
    B c({0}); // error
}

The error messages are:

f.cc: In function 'int main()':
f.cc:7:9: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
  B c({0}); // error

         ^
f.cc:7:9: note: candidates are:
f.cc:2:12: note: B::B(A)
 struct B { B(A);   };
        ^
f.cc:2:8: note: constexpr B::B(const B&)
 struct B { B(A);   };
        ^
f.cc:2:8: note: constexpr B::B(B&&)
like image 848
Jack Chin Avatar asked Sep 09 '15 02:09

Jack Chin


People also ask

What is direct initialization in C++?

Direct initialization is performed in the following situations: 2) initialization of an object of non-class type with a single brace-enclosed initializer (note: for class types and other uses of braced-init-list, see list-initialization) The effects of direct initialization are: The program is ill-formed

What is list initialization in C++?

List initialization is performed in the following situations: direct-list-initialization (both explicit and non-explicit constructors are considered) 1) initialization of a named variable with a braced-init-list (that is, a possibly empty brace-enclosed list of expressions or nested braced-init-lists)

What are the effects of direct initialization?

The effects of direct initialization are: The program is ill-formed The array is initialized as in aggregate initialization, except that narrowing conversions are allowed and any elements without an initializer are value-initialized .

How to initialize an object from an explicit set of arguments?

Initializes an object from explicit set of constructor arguments. T object ( arg1, arg2, ... ); T ( arg1, arg2, ... ) new T(args, ...) Class::Class() : member(args, ...) { ... } [arg] () { ... } Direct initialization is performed in the following situations:


1 Answers

As of the latest official standard, C++14, your first initialization is not ambiguous. [over.match.list]:

enter image description here

As no initializer-list constructors exist, we enter the "second phase". And now consider [over.best.ics]/4:

enter image description here

Our element is {0}. Hence this disallows the (user-defined) conversion {0} -> A for the copy constructor. Clearly, this doesn't apply if we aren't in the second phase of [over.match.list], so for your example with B c({0}), no list-initialization occurs for c and both constructors are considered.


CWG issue 1467

The first initialization is currently just as ambiguous as the second one. Compilers simply haven't implemented CWG #1467 yet - its resolution removed bullet point (4.5), quoted above.
See #2076, which opts to revert the change:

The resolution of issue 1467 made some plausible constructs ill-formed. For example,

struct A { A(int); };
struct B { B(A); };
B b{{0}};

This is now ambiguous, because the text disallowing user-defined conversions for B's copy and move constructors was removed from 13.3.3.1 [over.best.ics] paragraph 4.

"The text" is the aforementioned bullet point. Richard Smith proposes the following wording:

For non-class types, we allow initialization from a single-item list to perform a copy only if the element within the list is not itself a list (13.3.3.1.5 [over.ics.list] bullet 9.1). The analogous rule for this case would be to add back the bullet in 13.3.3.1 [over.best.ics] paragraph 4, but only in the case where the initializer is itself an initializer list:

        the second phase of 13.3.1.7 [over.match.list] when the initializer list has exactly one         element that is itself an initializer list, where the target is the first parameter of a constructor
        of class X, and the conversion is to X or reference to (possibly cv-qualified) X,

As the initializer {0} is itself an initializer list, that bullet point would make your first initialization well-formed again.

like image 148
Columbo Avatar answered Sep 23 '22 05:09

Columbo