【问题标题】:Is Type(::x); valid?是类型(::x);有效的?
【发布时间】:2014-07-08 03:07:27
【问题描述】:

虽然discussing Type(identifier); 语法以及它是如何声明的,但我遇到了Type(::x); 不使用 Clang。我希望给定一个全局变量x,它会将::x 视为一个表达式(::x + 2 有效)并将::x 转换为Type。但是,它给出了编译器错误。

这里是a short example

int x;

int main() {
    int(::x); //does not compile
    int(::x + 2); //compiles
}

Clang 3.5给出的编译器错误是:

错误:“x”的定义或重新声明无法命名全局范围

但是,GCC 4.9.0 可以很好地编译它。此代码是否有效?

【问题讨论】:

    标签: c++ compiler-errors expression declaration language-lawyer


    【解决方案1】:

    据我所知,draft C++ standard 部分 8.3 声明符的含义 段落 6 涵盖了这一点(强调我的未来):

    在声明 T D 中,其中 D 具有以下形式

    (D1)

    包含的 declarator-id 的类型与包含的 declarator-id 的类型相同 声明

    T D1

    括号不会改变嵌入的 declarator-id 的类型,但它们可以改变复杂的绑定 声明符。

    所以:

    int(::x);
    

    相当于:

    int ::x ;
    

    这显然是无效的,这也会产生相同的错误。所以gcc 4.9 在这里是不正确的,但由于这看起来在稍后发布的gcc 4.8.3 中已修复,我希望这也将在4.9 的后续版本中修复。虽然我在gcc 4.8.3 bugs fixed list 中没有看到任何与此问题的明显匹配项,但他们并没有声称这是一个完整的列表。

    第二种情况是函数显式类型转换,在 5.2.3 部分中进行了介绍 显式类型转换(函数表示法) 说:

    简单类型说明符 (7.1.6.2) 或类型名称说明符 (14.6) 后跟一个带括号的表达式列表构造一个值 给定表达式列表的指定类型。如果表达式列表是 单个表达式,类型转换表达式是等价的(在 定义性,如果在含义中定义)到相应的演员表 表达式 (5.4).[...]

    这是明确的,因为::x + 2 是一个表达式

    涵盖何时将语句视为声明或表达式的部分是6.8 歧义解决,它表示:

    涉及表达式语句的语法存在歧义 和声明:具有函数样式的表达式语句 显式类型转换(5.2.3)作为其最左边的子表达式可以是 与第一个声明符开始的声明没有区别 带有 (。在这些情况下,该语句是一个声明。 [注意:要 消除歧义,可能需要检查整个陈述以 确定它是表达式语句还是声明。这 消除许多例子的歧义。

    并提供以下示例:

    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
    

    注意:如果T 是一个,那么如果没有(),那么T ::D 是一个qualified-id,它包含在5.1 基本表达式的语法。

    更新

    提交了gcc bug report

    gcc 的回应是:

    当前 G++ 和 EDG 都将其视为有效表达式 (int)::x

    由于此回复暗示 clang 不正确(我不同意),我提交了 clang bug reportolder bug report 看起来相似,似乎不同意 gcc 回复.

    更新 2

    在回复clang bug report 时,Richard Smith 同意这应该被视为一项声明,并说:

    这并不意味着 clang 是不正确的;事实上,Clang 是正确的 在这里,据我所知。 (我还向 EDG 发送了错误报告。)

    也就是说,我们应该给出正确的“你遇到了一个令人烦恼的解析,这就是如何 在这种情况下消除歧义。

    更新 3

    gccconfirms 这是一个错误。

    【讨论】:

    • 您是否知道无论声明是否无效,都必须将其视为声明而不是表达式的部分? P.S.,如果struct Foo {}; 被用作类型,错误确实会改变:)
    • “在声明中 T D”(强调我的)。我们必须确定int (::x); 是一个声明,然后才能应用此子句。
    • Foo::x;Foo (::x); 给出不同的错误,其中 Foo 是一个类。
    • @MattMcNabb 这是因为在Foo ::x 的情况下,空格被删除并且被视为合格的ID。
    • @MattMcNabb fyi,gcc 确认这是一个错误
    【解决方案2】:

    这对我来说似乎是最令人烦恼的解析。如果可以将其解析为声明,它将是。第一个可以被解析为 int 变量的声明 (int ::x;),但 :: 在这种情况下是非法的。第二个 必须 是一个表达式,因此编译器会进行数学运算,将其转换为 int,然后丢弃结果。

    这是一个迂腐的问题,还是还有其他问题?如果您有想要解决的特定问题,附加信息可以为您的用例提供解决方法。

    【讨论】:

    • @Matt McNabb 这就是 C++ 语言的工作方式。这与我们需要模板的 typename 关键字的原因相同。
    • 我不清楚int::x; 应该是什么。 Foo::x; 会在Foo 的范围内查找x,这不是声明。看来int::x;int(::x);不一样
    • 有趣。我没有意识到无效的声明仍然适用于有效的表达式。
    • @MarkB 我们需要typename 来指示标识符是标识类型还是变量。我看不出这与int (::x); 的情况有何相似之处。规则是,如果它在句法上作为声明有效,那么它就是一个声明(即使它作为一个声明也是格式不正确的)。但是我看不出int (::x);(在块范围内)是声明的有效语法。
    猜你喜欢
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 2022-10-30
    • 1970-01-01
    • 2014-01-12
    相关资源
    最近更新 更多