- most_vexing_parse.cc
$ clang++ -std=c++14 most_vexing_parse.cc
most_vexing_parse.cc:22:25: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
TimeKeeper time_keeper(Timer());
^~~~~~~~~
most_vexing_parse.cc:22:26: note: add a pair of parentheses to declare a variable
TimeKeeper time_keeper(Timer());
^
( )
most_vexing_parse.cc:23:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a structure or union
return time_keeper.get_time();
~~~~~~~~~~~^~~~~~~~~
1 warning and 1 error generated.
- prohibit_narrowing_conversion.cc
$ clang++ -std=c++14 prohibit_narrowing_conversion.cc
prohibit_narrowing_conversion.cc:13:14: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
int sum3{x + y + z}; // compile error
^~~~~~~~~
prohibit_narrowing_conversion.cc:13:14: note: insert an explicit cast to silence this issue
int sum3{x + y + z}; // compile error
^~~~~~~~~
static_cast<int>( )
1 error generated.
- stronglly_prefer_initializer_list_constructor.cc
$ clang++ -std=c++14 stronglly_prefer_initializer_list_constructor.cc && ./a.out
constructor 1
constructor 1
constructor 2
constructor 2
$
$ clang++ -std=c++14 -DSTD_INITIALIZER_LIST_CONSTRUCTOR stronglly_prefer_initializer_list_constructor.cc && ./a.out
constructor 1
constructor 3
constructor 2
constructor 3
- empty_brace.cc
$ clang++ -std=c++14 empty_brace.cc && ./a.out
empty_brace.cc:17:14: warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
Widget w1(); // most vexing parse! w1 will be interpreted as a function declare
^~
empty_brace.cc:17:14: note: remove parentheses to declare a variable
Widget w1(); // most vexing parse! w1 will be interpreted as a function declare
^~
1 warning generated.
default constructor
default constructor
constructor takes initilaizer_list
constructor takes initilaizer_list
- vector_sample.cc
$ clang++ -std=c++14 vector_sample.cc && ./a.out
v1 20 20 20 20 20 20 20 20 20 20
v2 10 20
Index | Syntax | Comment |
---|---|---|
1 | int x(0); |
initializer is in parentheses |
2 | int x = 0; |
initializer follows = |
3 | int x{ 0 }; |
initializer is in braces i.e. Uniform Initialization |
4 | int x = {0}; |
equal to int x{ 0 }; |
- For built-in types like
int
, they're no difference in practice. - For user-defined types, different function calls may be involved.
Item | Sample | Able to do by () |
Able to do by = |
---|---|---|---|
Initialize container with contents | // initialize a vector with contents 1, 3 and 5. std::vector<int> v{1, 3, 5}; |
No | No |
Initialize non-static member | private: int x{ 0 }; |
No | Yes |
Initialize uncopyable object | std::atomic<int> a{ 0 }; |
Yes | No |
Prohibit implicit narrowing conversions among built-in types | double x, y, z; int sum1{ x + y + z}; //compile error |
No | No |
Avoid C++ 's Most vexing parse |
Widget w1; // OK, default constructor Widget w2(); // ERROR, most vexing parse! Widget w3{}; // OK, default constructor |
No | No |
-
Unusual behavior when
{ xxx }
+std::initializer_list
+constructor overload
- In constructor calls,
(xxx)
and{ xxx }
have the same meaning as long asstd::initializer_list
parameters are not involved. - If there's one or more constructors declare a parameter of type
std::intializer_list
, calls using the{ xxx }
stronglly prefer the overloads takingstd::initializer_list
, even sometimes it will lead to compilation error. (go through the amazing samples from the book) - Empty
{}
always means no arguments, not an emptystd::intializer_list
.
- In constructor calls,
-
Significant differences when initialize
std::vector<T>
by{xxx}
and(xxx)
//use non-std::intializer_list constructor
//i.e. create 10 element std::vector, all elements have value 20
std::vector<int>(10, 20);
//use std::initializer_list constructor
//i.e. create 2 element std::vector, element values are 10 and 20
std::vector<int>{10, 20};
- As a class author, it's best to design your constructors so that the overload called isn't affected by whether clients use
()
or{}
. In another word, design your classes to avoid the error in the design ofstd::vector
; - As a class client, choose carefully between
()
and{}
when creating objects.- Most developers end up choosing one kind of delimiter as a default, using the other only when they have to. E.g. Braces-by-default or go-parentheses-go.
- If you're a template author, in general it's not possible to know
()
or{}
should be used.- This is precisely the problem faced by the Standard Library function
std::make_unique
andstd::make_shared
. They resolve the problem by internally using()
and by documenting this decision as part of their interfaces.
- This is precisely the problem faced by the Standard Library function