11

以下代码

#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 中的错误还是 Clang 的扩展/错误?

4

2 回答 2

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())());
                                                ^

相关制作为5.4p2:

演员表

  • 一元表达式
  • ( type-id )强制转换表达式

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

后缀表达式

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

后缀表达式在哪里,(std::random_device())表达式列表被省略。

我已经在 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

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

((std::less<int>()))(1, 2);
于 2013-02-06T17:55:12.593 回答
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带有未命名参数的函数声明)。所以问题是:它可以被解释为其他什么吗?如果是这样,并且如果它在这种情况下有意义,那么编译器应该考虑将整个表达式解析为 object 的构造b

这可能是 GCC 和 Clang 不同意的根本点:

int main()
{
    (A())(); // OK for Clang, ERROR for GCC
}

A除了尝试构造一个临时类型并调用其调用运算符之外,我看不出如何将上述内容解释为其他任何东西。它不能是函数声明,因为如果A被解释为返回类型,则名称丢失(反之亦然)。

另一方面,(A())是创建临时类型的有效表达式A,并且该临时支持调用运算符(其返回类型与 的构造函数接受的类型相同B)。因此,(A())()应该是 type 的有效表达式bool

由于这个原因,我认为GCC的解析是错误的。

于 2013-02-06T15:16:17.620 回答