Date: Tue, 05 Oct 2021 14:11:40 +0200
Hello,
I would like to report what I will call "constructor ambiguity" for
classes which have multiple constructors, one of which have takes an
initializer list.
The ambiguity is for us humans, not the compiler, and is due to the two
things:
1. The same syntax is used for uniform initialization and
initializer lists.
2. Any constructor taking an initializer list is preferred when
braces are used.
For example:
std::string sa(32, 'A'); // Creates a string of 32 characters i.e. "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
std::string sb{32, 'A'}; // Creates a string of 2 characters i.e. " A"
std::vector<int> va(10, -1); // Creates a vector of 10 elements, each one initialized to -1
std::vector<int> vb{10, -1}; // Creates a vector of 2 elements (10 and -1)
The code looks very similar and yet the results are very different.
This is unfortunate because uniform initialization is preferred
especially as it can avoid bugs due to unintential casts and
truncation/narrowing of values.
I find this ambiguity unnecessary as if the intent is to provide an
initializer list, then this can be done explicitly:
std::vector<int> vb1({10, -1}); // Creates a vector of 2 elements (10 and -1)
std::vector<int> vb2{{10, -1}}; // Creates a vector of 2 elements (10 and -1)
This preference to use a constructor taking an initializer list can
easily break code if such a constructor is added at a later date. For
example:
struct A {
explicit A(int);
};
A a{2}; // Create an object a of type A
Then later on an initializer list constructor is added:
struct A {
explicit A(int);
A(const std::initializer_list<int>&)
};
Now the call to create object 'a' will use the constructor taking an
initializer list which, of course, can do something completely
different. It could be extremely difficult to find why there was such
a change in behaviour.
I apologize but I do not know if this has already been mentioned or
addressed. If not, what do you think of this? Is this considered to
be one of the many idioms of C++?
Gawain Bolton
I would like to report what I will call "constructor ambiguity" for
classes which have multiple constructors, one of which have takes an
initializer list.
The ambiguity is for us humans, not the compiler, and is due to the two
things:
1. The same syntax is used for uniform initialization and
initializer lists.
2. Any constructor taking an initializer list is preferred when
braces are used.
For example:
std::string sa(32, 'A'); // Creates a string of 32 characters i.e. "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
std::string sb{32, 'A'}; // Creates a string of 2 characters i.e. " A"
std::vector<int> va(10, -1); // Creates a vector of 10 elements, each one initialized to -1
std::vector<int> vb{10, -1}; // Creates a vector of 2 elements (10 and -1)
The code looks very similar and yet the results are very different.
This is unfortunate because uniform initialization is preferred
especially as it can avoid bugs due to unintential casts and
truncation/narrowing of values.
I find this ambiguity unnecessary as if the intent is to provide an
initializer list, then this can be done explicitly:
std::vector<int> vb1({10, -1}); // Creates a vector of 2 elements (10 and -1)
std::vector<int> vb2{{10, -1}}; // Creates a vector of 2 elements (10 and -1)
This preference to use a constructor taking an initializer list can
easily break code if such a constructor is added at a later date. For
example:
struct A {
explicit A(int);
};
A a{2}; // Create an object a of type A
Then later on an initializer list constructor is added:
struct A {
explicit A(int);
A(const std::initializer_list<int>&)
};
Now the call to create object 'a' will use the constructor taking an
initializer list which, of course, can do something completely
different. It could be extremely difficult to find why there was such
a change in behaviour.
I apologize but I do not know if this has already been mentioned or
addressed. If not, what do you think of this? Is this considered to
be one of the many idioms of C++?
Gawain Bolton
Received on 2021-10-05 07:11:47