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

偶尔善良 提交于 2019-12-01 17:45:34

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<S> realized that the syntax would be something like that:

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

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

std::vector<int> 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<int> v0(1, 2); // one element with value 2
std::vector<int> v1{1, 2}; // two elements: 1 and 2

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

I don't like this style at all, as it makes me think the object does not have a regular constructor.

If it's an aggregate type, aggregate initialization is performed. Otherwise, it considers the constructors. If it makes you think that the class is an aggregate, that is not a language problem.

Is there a reason to now prefer this syntax over regular constructor calls?

If you're a proponent of uniform initialization yes. If you're not, you can stick with the old style. Note that the other answer talks about std::initializer_list but this doesn't apply to your question whatsoever, since you have no constructor which takes a std::initializer_list. Braced-init-lists and std::initializer_list are separate concepts. It's best not to get them confused this early on.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!