Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use C++11 uniform initialization syntax?

I cannot understand when and how to use the new uniform initialization syntax in C++11.
For example, I get this:

std::string a{"hello world"}; // OK
std::string b{a};  // NOT OK

Why does it not work in the second case? The error is:

error: no matching function for call to ‘std::basic_string<char>::basic_string(<brace enclosed initializer list>)’    

with this version of g++ g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2.

And with primitive data, what syntax should I use?

int i = 5;
int i{5};
int i = {5};
like image 560
smancill Avatar asked Sep 30 '11 14:09

smancill


People also ask

What is uniform initialization in C?

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.

What is initialization expression in C?

In C/C99/C++, an initializer is an optional part of a declarator. It consists of the '=' character followed by an expression or a comma-separated list of expressions placed in curly brackets (braces).

What is uniform C++?

uniform, a C++ code which returns a sequence of uniformly distributed pseudorandom numbers. The fundamental underlying random number generator is based on a simple, old, and limited linear congruential random number generator originally used in the IBM System 360.

How do you initialize a class in C++?

There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.


2 Answers

The compile error for

// T t{u};
std::string a;
std::string b{a};

Is a combination of four things

  • The draft until not long ago said that if T has an initializer list constructor (std::string has one, taking char elements), that the initializer list is passed itself as an argument. So the argument to the constructor(s) is not a, but {a}.

  • The draft says that an initializer list initializing a reference is done not by direct binding, but by first constructing a temporary out of the element in the initializer list, and then binding the target reference to that temporary.

  • The draft says that when initializing a reference by an initializer list, when the initialization of the reference is not direct binding, that the conversion sequence is a user defined conversion sequence.

  • The draft says that when passing the initializer list itself when considering constructors of class X as candidates in an overload resolution scenario in a context like the above, then when considering a first constructor parameter of type "reference to cv X" (cv = const / volatile) - in other words highly likely a copy or move constructor, then no user defined conversions are allowed. Otherwise, if such a conversion would be allowed, you could always run in ambiguities, because with list initialization you are not limited to only one nested user defined conversion.

The combination of all the above is that no constructor can be used to take the {a}. The one using initializer_list<char> does not match, and the others using string&& and const string& are forbidden, because they would necessitate user defined conversions for binding their parameter to the {a}.

Note that more recent draft changed the first rule: They say that if no initializer list constructor can take the initializer list, that then the argument list consists of all the elements of the initializer list. With that updated rule, your example code would work fine.

like image 65
Johannes Schaub - litb Avatar answered Sep 27 '22 01:09

Johannes Schaub - litb


The first example is supposed to work, calling the copy constructor. If you're using GCC, this has been fixed in 4.6.

The last examples have a slight non stylistic difference.

int i = 5.0;   // fine, stores 5
int i{5.0};    // won't compile!
int i = {5.0}; // won't compile!

The difference is that uniform initialization syntax does not allow narrowing conversions. You may want to take this into consideration when choosing between them.

like image 28
R. Martinho Fernandes Avatar answered Sep 25 '22 01:09

R. Martinho Fernandes