6

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.

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • The new construction syntax with curly braces is NOT supposed to be a general replacement for all the previous construction syntaxes. Unfortunately, this is a VERY common misunderstanding. – Mooing Duck May 15 '13 at 16:42

1 Answers1

9

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.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • Excellent point. That could have been fixed by defining the second version as `std::vector v{{1,1}};`. – bitmask Sep 16 '12 at 20:05
  • 2
    @bitmask these situations actually aren't that rare, since an initialization list constructor trumps all other constructors. Related question [here](http://stackoverflow.com/questions/9976927/when-to-use-the-brace-enclosed-initializer/9977266#9977266). – juanchopanza Sep 16 '12 at 20:12
  • 3
    @bitmask I don't think that would be an improvement. All that would do is change the syntax you have to use in order to indicate a preference for initializer_list constructors or not. Basically braces would be exactly equivalent to parens and to use an initializer list in either case would require a nested set of braces, meaning that the syntax would not be uniform with array initialization. – bames53 Sep 16 '12 at 20:12
  • @bames53: Right, didn't think about arrays. – bitmask Sep 16 '12 at 20:15
  • In my mind, I use `{}` to initialize from a list of values (including one or zero values), and `()` for all other constructors. This resolves all ambiguities. – Mooing Duck May 15 '13 at 16:45
  • @MooingDuck That works. I prefer to just always use `{}` and to avoid using or writing constructors that can't be used by brace initialization. – bames53 May 15 '13 at 16:59