用临时函数对象进行全局初始化

lve*_*lla 11 c++ gcc clang c++11

以下代码

#include <random>
std::mt19937 generator((std::random_device())());
Run Code Online (Sandbox Code Playgroud)

使用clang编译文件:

$ clang++ -c -std=c++0x test.cpp
Run Code Online (Sandbox Code Playgroud)

但是gcc失败了:

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

该代码在C++ 11中是否有效?这是GCC中的错误还是Clang的扩展错误?

eca*_*mur 6

gcc将子表达式解析(std::random_device())()为函数类型的强制转换std::random_device().它有助于查看icc的错误输出,这比gcc的信息量更多:

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())());
                                                ^
Run Code Online (Sandbox Code Playgroud)

相关产量为5.4p2:

cast-expression:

  • 一元表达式
  • (type-id)cast-expression

由于一对空括号()不是一元表达式,因此该生产不可用,编译器应从5.2p1中选择生产:

后缀表达式:

  • [...]
  • 后缀表达式(表达式列表选择)
  • [...]

其中postfix-expression是,(std::random_device())并且省略了expression-list.

我已经在gcc bugzilla上提交了http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239,看起来很快就应该解决了.

请注意,如果要向其提供参数,operator()则8.2p2需要编译器将表达式解析为强制转换,即使转换为函数类型是非法的(如果有多个参数,则参数列表将被解析为表达式使用逗号运算符:

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

写这个的正确方法(除了使用C++ 11通用初始化器语法之外)是添加另一层括号,因为type-id不能包含外括号:

((std::less<int>()))(1, 2);
Run Code Online (Sandbox Code Playgroud)