Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is it parsed: constructing unnamed temporary with braced init list

Tags:

c++

c++11

I recently yet again encountered the notation

( const int[10] ){ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }

As I recall it's permitted in both C and C++, but via quite different language mechanisms.

I believed that in C++ the formal view is that it's a construction of an unnamed temporary via an epxlicit type conversion (T) cast-expression that would reduce to a static_cast, that constructs an object via C++11 §5.2.9/4:

an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5)

However, the cast-expression syntax is defined by C++11 §5.4/2 as being either unary-expression or, recursively, a ( type-id ) cast-expression, where the single base case is reduction to unary-expression.

And as far as I can tell a braced init-list is not an expression?

An alternative view could be that it’s an explicit type conversion via functional notation, C++11 §5.2.3/3,

a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type

but as far as I can tell a simple-type-specifier can’t involve parentheses, and a typename-specifier involves the keyword typename?

like image 896
Cheers and hth. - Alf Avatar asked Jun 24 '14 11:06

Cheers and hth. - Alf


1 Answers

Per C99 (well, actually N1256 which is the prior draft) 6.5.2.5/4:

A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.

Some compilers - at least g++ and clang - provide C99 compound literals in C++ as an extension. Semantically, the expression

( const int[10] ){ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }

is a literal of type const int[10]: decltype((const int[10]){ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }) is in fact const int[10]. Note well: There's some disagreement among g++ versions about the exact type: g++ versions before 4.9 says that decltype((const int[10]){ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }) is const int(&)[10]. See this demonstration program.

You can achieve the same result in standard C++ with explicit type conversion via functional notation, but you must define a type alias for the array type since functional notation requires a simple-type-specifier:

using foo = const int[10];
foo{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

or Xeo's general alias template:

template <typename T>
using foo = T;
foo<const int[10]>{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
like image 150
Casey Avatar answered Oct 07 '22 18:10

Casey