Why does C++ list initialization also take regular constructors into account?

后端 未结 2 1654
谎友^
谎友^ 2021-01-18 07:49

In C++ when using initializer_list syntax to initialize an object, the regular constructors of the object also participate in overload resolution, when no other list initial

2条回答
  •  遥遥无期
    2021-01-18 08:39

    Essentially it is a mess up. For C++11 it was attempted to create one uniform way to initialize objects instead of multiple approaches otherwise necessary:

    • T v(args...); for the usual case
    • T d = T(); when using the default constructor for stack-based objects
    • T m((iterator(x)), iterator()); to fight the Most Vexing Parse (note the extra parenthesis around the first parameter)
    • T a = { /* some structured values */ }; for aggregate initialization

    Instead the Uniform Initialization Syntax was invented:

    T u{ /* whatever */ };
    

    The intention was that uniform initialization syntax would be used everywhere and the old stule would go out of fashion. Everything was fine except that proponents of initialization from std::initializer_list realized that the syntax would be something like that:

    std::vector vt({ 1, 2, 3 });
    std::vector vu{{ 1, 2, 3 }};
    

    That was considered unacceptable and uniform initialization syntax was irreparably compromised to allow the so much better

    std::vector vx{ 1, 2, 3 };
    

    The problem with this mixture is that it now is sometimes unclear what is actually meant and uniform initialization syntax isn’t uniform any more. It is still necessary in some contexts (especially to value initialize stack-based objects in generic code) but it isn’t the correct choice in all cases. For example, the following two notations were meant to mean the same thing but they don’t:

    std::vector v0(1, 2); // one element with value 2
    std::vector v1{1, 2}; // two elements: 1 and 2
    

    tl;dr: initializer list and uniform initialization syntax are the two separate notations. Sadly, they conflict.

提交回复
热议问题