使用临时函数对象进行全局初始化
Global initialization with temporary function object
以下代码
#include <random>
std::mt19937 generator((std::random_device())());
只编译带有clang的文件:
$ clang++ -c -std=c++0x test.cpp
但使用gcc:失败
$ g++ -c -std=c++0x test.cpp
test.cpp:3:47: erro: expected primary-expression before ‘)’ token
该代码在C++11中有效吗?这是GCC中的bug还是Clang的扩展/bug?
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())());
^
相关产量为5.4p2:
强制转换表达式:
- 一元表达式
- (类型id)强制转换表达式
由于一对空括号()
不是一元表达式,因此该生成不可用,编译器应从5.2p1:中选择生成
后缀表达式:
- […]
- 后缀表达式(表达式列表opt)
- […]
其中后缀表达式是(std::random_device())
,并且省略表达式列表。
我已提交http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239关于gcc bugzilla,它看起来应该很快得到解决。
请注意,如果向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
写这篇文章的正确方法(除了使用C++11通用初始化器语法)是添加另一层括号,因为类型id不能包含外括号:
((std::less<int>()))(1, 2);
GCC处理函数声明的方式似乎有问题。举个例子:
struct A
{
bool operator () () { return true; }
};
struct B
{
B(bool) { }
};
B b(( // This cannot be parsed as a function declaration,
A()() // and yet GCC 4.7.2 interprets it as such:
)); // "error: 'type name' declared as function returning
// a function B b((A()()));"
int main() { }
由于A()()
周围存在额外的括号,因此语法形式B b(( A()() ));
不能被解析为函数的声明。
您的问题示例中的声明略有不同:
B b(
(A())()
);
然而,即使在这种情况下,(A())()
也不能被解释为返回返回A
的函数的类型(总是试图将b
视为具有未命名参数的函数声明)。所以问题是:它能被解释为其他东西吗?如果是这样,并且在这种情况下有意义,那么编译器应该考虑将整个表达式解析为对象b
的构造。
这可能是GCC和Clang不同意的根本点:
int main()
{
(A())(); // OK for Clang, ERROR for GCC
}
除了试图构造A
类型的临时并调用其调用运算符之外,我看不出以上内容如何被解释为其他内容。它不能是函数声明,因为如果A
被解释为返回类型,那么名称就会丢失(反之亦然)。
另一方面,(A())
是用于创建类型为A
的临时的有效表达式,该临时支持调用运算符(其返回类型与B
的构造函数接受的类型相同)。因此,(A())()
应该是bool
类型的有效表达式。
出于这个原因,我认为GCC的解析是错误的。
- 内存清理程序报告全局对象构造中未初始化值的使用
- 使用 std::ios_base::Init 正确初始化全局变量
- 在C++中全局初始化类的正确方法
- C++ 未初始化的本地(非全局)int 数组中的元素类型到底是什么?
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 在 glsl 中初始化全局变量?
- 初始化与函数输入相关的全局数组
- 对全局变量的非常量引用的初始化无效
- 视觉C++:在 DLL 加载期间,全局变量初始化顺序是否具有确定性?
- C++本地/全局对象的初始化
- 使用constexpr的全局初始化顺序
- 未显式初始化C++全局变量时发出警告?
- 哪个函数负责C++全局范围内的类对象初始化?
- 使用全局变量初始化不同编译单元中的其他全局变量
- 如何使用GDB跟踪Main()之前初始化的所有静态全局变量
- 实例的全局初始化
- 全局初始化c++类
- C++11:赋值运算符是否阻止一个类型成为POD,从而全局初始化
- 为什么人们不全局初始化 i?
- 使用临时函数对象进行全局初始化