My question is about the confusion in C++ default class member initialization between using an initializer list and calling a constructor.
There is no ambiguity in the language but a possible confusion in the developer's mind, leading to obscure bugs. Do you know a good way to detect or avoid this confusion?
When declaring a variable, there is no confusion because using an initializer_list and calling a constructor use distinct syntaxes:
using block = std::vector<int>;
block a{4, 5}; // brackets => initializer list, 2 elements, with values 4 and 5
block b(4, 5); // parentheses => constructor call, 4 elements, all with value 5
Calling a constructor in a default member initializer uses braces instead of parentheses. However, when the type of the member accepts a initializer_list, this becomes confusing:
class A
{
public:
A(int size, int value);
};
class C
{
public:
A a{4, 5}; // Call constructor A(4, 5)
block b{4, 5}; // Initializer list, not constructor call, even though same syntax
block c{block(4, 5)}; // Force a constructor call, but awkward syntax
};
The confusion comes from whether the member's type accepts an initializer_list or not.
Do you know a nice way to handle this?
In-class member initializers also support
=:This is slightly less awkward than
block b{block(4, 5)};.