c++ - g++ 拒绝,clang++ 接受 : foo(x) ("bar") ("baz");

标签 c++ syntax g++ clang++ most-vexing-parse

有人拥有 asked前几天为什么有些东西用clang编译,而不是用gcc编译。我直观地理解正在发生的事情并能够帮助这个人,但这让我想知道——根据标准,哪个编译器是正确的?这是代码的简化版本:

#include <iostream>
#include <string>

class foo
{
public:
    foo(const std::string& x):
        name(x)
    { }
    foo& operator()(const std::string& x)
    {
        std::cout << name << ": " << x << std::endl;
        return (*this);
    }
    std::string name;
};

int main()
{
    std::string x = "foo";
    foo(x)("bar")("baz");
    return 0;
}

使用 clang++ 可以正常编译,但是 g++ 给出以下错误:

runme.cpp: In function ‘int main()’:
runme.cpp:21:11: error: conflicting declaration ‘foo x’
    foo(x)("bar")("baz");
        ^
runme.cpp:20:17: error: ‘x’ has a previous declaration as ‘std::string x’
    std::string x = "foo";

如果我在第 21 行添加一对括号,g++ 很高兴:

(foo(x))("bar")("baz");

换句话说,g++ 将这一行解释为:

foo x ("bar")("baz");

我认为它是 g++ 中的错误,但我想再次询问标准专家,哪个编译器出错了?

PS:gcc-4.8.3、clang-3.5.1

最佳答案

据我所知,这在草案 C++ 标准部分 6.8 歧义解决 中有所涉及,它说表达式语句和声明之间可能存在歧义,并说:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [ Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. This disambiguates many examples. [ Example: assuming T is a simple-type-specifier (7.1.6),

并给出以下例子:

T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement

T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration

然后说:

The remaining cases are declarations. [ Example:

class T {
    // ...
   public:
    T();
    T(int);
    T(int, int);
};
T(a); // declaration
T(*b)(); // declaration
T(c)=7; // declaration
T(d),e,f=3; // declaration
extern int h;
T(g)(h,2); // declaration

—end example ] —end note ]

似乎这种情况属于声明示例,特别是最后一个示例似乎在 OP 中提出了这种情况,因此 gcc 将是正确的。

上面提到的相关部分5.2.3 显式类型转换(功能表示法)说:

[...] If the type specified is a class type, the class type shall be complete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.

8.3 声明符的含义其中说:

In a declaration T D where D has the form

( D1 ) 

the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration

T D1

Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex declarators.

更新

我最初使用的是 N337但是如果我们看一下 N4296 6.8 部分已更新,现在包含以下注释:

If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not apply.

这意味着 gcc 不正确,因为:

foo x ("bar")("baz");

不能是一个有效的声明,我最初将第 2 段解释为如果你的 case 以以下任何一个开头,那么它就是声明,这可能是 gcc 实现者也被解释。

我应该对第 2 段更加怀疑,因为第 2 段的唯一规范部分确实没有提及第 1 段和似乎对一个不规范的例子提出了要求。我们可以看到,段落 2 中的语句现在实际上是一个更有意义的注释。

作为 T.C.如下所述,第 2 段实际上从来都不是规范的,它只是这样出现,他 linked to the change that fixed it .

关于c++ - g++ 拒绝,clang++ 接受 : foo(x) ("bar") ("baz");,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28283215/

相关文章:

matlab - 缩进会影响 Matlab 代码吗?

c++ - ISO C++ 的带有零参数的可变参数宏

gdb - gdb 如何重建 C++ 的堆栈跟踪?

c++ - 类内的多个线程访问数据

c++ - 为什么我需要将 lib 文件链接到我的项目?

C++读取字符串段错误

gcc - 与具有依赖关系的动态库链接

c++ - 为什么 CoCreateInstanceFromApp 在 ARM 构建中缺少 x64 构建?

Python/Ubuntu - 将目录复制到新目录(目录路径不正确?)

javascript - 子类声明中的赋值 - React.Component