Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How generic is the {} construction syntax?

In a talk about initialization lists, I understood Stroustrup basically saying that the new construction syntax with curly braces is supposed to be a general replacement for all the previous construction syntaxes:

X x1(); // most vexing parse ... doesn't work as intended
X x2(x1);
X x3 = x1;
X x4 = X();

Instead, the new syntax is supposed to be used uniformly as a possible replacement that you can use in every situation ... again, that's the core message that I took from his talk. Maybe I misunderstood him.

So, the question is, how generic is this syntax? Is it possible to never use old-style construction in new C++11 code or are there situations where you have to revert?


This question was triggered/motivated when I encountered the following error, which I believe is an error in the compiler (but I'd be happy to be corrected).

struct X {};

int main() {
  X x;
  X& y{x}; // works with (x)
  X& z{y}; // works with (y)
}

Which doesn't compile on g++ 4.7.1 nor does it on ideone's 4.5.1.

prog.cpp: In function 'int main()':
prog.cpp:5:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'
prog.cpp:6:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'

Note that it works when I replace X with int.

like image 435
bitmask Avatar asked Sep 16 '12 20:09

bitmask


1 Answers

Brace initialization works everywhere an initializer is used. There are situations where you have to use parens in order to access a constructor that a brace initializer cannot access, but they are rare.

std::vector<int> v(1,1);
std::vector<int> v{1,1};

vector<int> happens to have a specialized constructor that takes two ints and is therefore ambiguous with trying to construct a vector two ints long. The ambiguous constructor exists only for backwards compatibility. New classes should not be defined with any constructors that would conflict with an initializer_list.

The ambiguity is resolved by the fact that brace initialization syntax prefers initializer_list constructors over other constructors that would otherwise match. If you want to resolve the ambiguity in favor of using the non-initializer_list constructor then you can't use brace initialization.


Bjarne Stroustrup writes

The uniform use of {} initialization only became possible in C++11, so older C++ code uses () and = initialization. Consequently, the () and = may be more familiar to you. However, I don't know any logical reason to prefer the () notation except in the rare case where you need to distinguish between initialization with a list of elements and a list of constructor arguments.

                                                         — The C++ Programming Language, Fourth Edition §17.3.2.1


Your example code is perfectly legal and should work as expected. The error you're getting is simply a bug in GCC. Clang and VC++ 2012 both accept the code.

like image 62
bames53 Avatar answered Sep 19 '22 12:09

bames53