Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global initialization with temporary function object

Tags:

c++

gcc

c++11

clang

The following code

#include <random>
std::mt19937 generator((std::random_device())());

compiles just file with clang:

$ clang++ -c -std=c++0x test.cpp

but fails with gcc:

$ g++ -c -std=c++0x test.cpp 
test.cpp:3:47: erro: expected primary-expression before ‘)’ token

Is that code valid in C++11? Is it a bug in GCC or a extension/bug of Clang?

like image 697
lvella Avatar asked Feb 06 '13 15:02

lvella


1 Answers

gcc is parsing the subexpression (std::random_device())() as a cast to the function type std::random_device(). It helps to look at icc's error output, which is slightly more informative than gcc's:

source.cpp(6): error: cast to type "std::random_device ()" is not allowed
  std::mt19937 generator((std::random_device())());
                          ^

source.cpp(6): error: expected an expression
  std::mt19937 generator((std::random_device())());
                                                ^

The relevant production is 5.4p2:

cast-expression:

  • unary-expression
  • ( type-id ) cast-expression

Since an empty pair of parentheses () is not a unary-expression, this production is unavailable and the compiler should select the production from 5.2p1:

postfix-expression:

  • [...]
  • postfix-expression ( expression-listopt )
  • [...]

where the postfix-expression is (std::random_device()) and the expression-list is omitted.

I've filed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239 on gcc bugzilla, and it looks like it should be resolved shortly.

Note that if you are supplying arguments to the operator() then the compiler is required by 8.2p2 to parse the expression as a cast, even though it is illegal to cast to a function type (if there are multiple arguments, the argument list is parsed as an expression using the comma operator:

(std::less<int>())(1, 2);
^~~~~~~~~~~~~~~~~~ illegal C-style cast
 ^~~~~~~~~~~~~~~~ type-id of function type std::less<int>()
                  ^~~~~~ argument of C-style cast
                    ^ comma operator

The correct way to write this (other than using C++11 universal initializer syntax) is to add another layer of parentheses, since a type-id cannot contain outer parentheses:

((std::less<int>()))(1, 2);
like image 62
ecatmur Avatar answered Oct 04 '22 03:10

ecatmur