130 lines
3.0 KiB
Plaintext
130 lines
3.0 KiB
Plaintext
== Why is this an issue?
|
||
|
||
C+11 introduced “Uniform initialization”/"list initialization". It is a way to initialize an object from a braced-init-list. This adds a third way to initialize objects in {cpp} on top of parentheses and equal signs.
|
||
|
||
----
|
||
int a{1}; // braces initialization
|
||
int b(1); // parentheses initialization
|
||
int c=1; // equal sign initialization
|
||
----
|
||
“Uniform initialization” was introduced to address the confusion of the many initialization syntaxes in {cpp} and to give a syntax that, in concept, can be used in all initialization scenarios. It helps to:
|
||
|
||
* Initialize container in a way that wasn't possible before:
|
||
|
||
----
|
||
// Before
|
||
std::vector<int> v;
|
||
v.push_back(1);
|
||
v.push_back(2);
|
||
// After
|
||
std::vector<int>{1,2,3};
|
||
----
|
||
|
||
* Avoid narrowing:
|
||
|
||
----
|
||
double d=2.5;
|
||
int i{d}; // Compilation error
|
||
----
|
||
|
||
* Avoid the most vexing parse:
|
||
|
||
----
|
||
class A{};
|
||
A a(); // Compilation error declares a function named a that returns A.
|
||
A a{}; // Call A constructor
|
||
----
|
||
|
||
That is why “Uniform initialization” should be preferred.
|
||
|
||
|
||
=== Noncompliant code example
|
||
|
||
[source,cpp]
|
||
----
|
||
struct A {
|
||
A(int i, int j, int z) {
|
||
...
|
||
}
|
||
};
|
||
|
||
void f() {
|
||
A a(1,2,3); // Noncompliant
|
||
}
|
||
|
||
struct B {
|
||
A a = A(1, 2, 3); // Noncompliant
|
||
};
|
||
----
|
||
|
||
|
||
=== Compliant solution
|
||
|
||
[source,cpp]
|
||
----
|
||
struct A {
|
||
A(int i, int j, int z) {
|
||
...
|
||
}
|
||
};
|
||
|
||
void f() {
|
||
A a{1,2,3};
|
||
}
|
||
|
||
struct B {
|
||
A a{1, 2, 3};
|
||
};
|
||
----
|
||
|
||
|
||
=== Exceptions
|
||
|
||
* In some situations, “Uniform initialization” has surprising behavior. for example, in constructor overload resolution, “Uniform initialization” prefers the constructor with "std::initializer_list" as a parameter if possible, even if another constructor seems like a better match. Like in the "std::vector" case, you might need to go back to parentheses in order to call the non "intializer_list" constructor:
|
||
|
||
[source,cpp]
|
||
----
|
||
vector<int> v1(5, 10); // 5 copies of the value 10
|
||
----
|
||
|
||
* When "=" is after "auto". This might be needed to enforce deduction to initializer_list:
|
||
|
||
[source,cpp]
|
||
----
|
||
auto i1 {1}; // int with the value 1
|
||
auto i2 = {1}; // std::initializer_list<int> with an element equal to 1
|
||
----
|
||
|
||
* In single argument cases, "=" is okay:
|
||
|
||
[source,cpp]
|
||
----
|
||
int i = 39;
|
||
----
|
||
|
||
* When the braces are after the "=":
|
||
|
||
[source,cpp]
|
||
----
|
||
vector<int> v = { 1, 2, 4 };
|
||
----
|
||
|
||
|
||
== Resources
|
||
|
||
* {cpp} Core Guidelines - https://github.com/isocpp/CppCoreGuidelines/blob/e49158a/CppCoreGuidelines.md#es23-prefer-the\--initializer-syntax[ES.23: Prefer the `{}`-initializer syntax]
|
||
|
||
|
||
ifdef::env-github,rspecator-view[]
|
||
'''
|
||
== Comments And Links
|
||
(visible only on this page)
|
||
|
||
=== on 11 May 2020, 09:05:55 Geoffray Adde wrote:
|
||
* The description is crystal clear! I love the summary about initialization.
|
||
* In single argument cases, "=" is okay: => maybe builtin single argument case ?
|
||
* In some situations, “Uniform initialization” has surprising behavior. => somehow to me, it makes sense because the curly braces syntax seems to indicate initializer list.
|
||
* Do we need more examples?
|
||
|
||
endif::env-github,rspecator-view[]
|