【问题标题】:Is gcc or clang correct about this behavior?gcc 或 clang 对这种行为是否正确?
【发布时间】:2018-07-24 02:33:59
【问题描述】:

我有一个小玩具程序:

static int value = 0;

int function(int &value=value) {
    return value;
}

int main() {
    function();
}

使用 g++ 7.2 编译:

g++ -std=c++11 -Wall -Wextra test.cc -o test

没问题。

用clang++-3.9编译:

clang++-3.9 -std=c++11 -Wall -Wextra test.cc -o test

test.cc:3:25: error: default argument references parameter 'value'
int function(int &value=value) {
                        ^~~~~
test.cc:8:5: error: no matching function for call to 'function'
    function();
    ^~~~~~~~
test.cc:3:5: note: candidate function not viable: requires single argument 'value', but no arguments were provided
int function(int &value=value) {
    ^
2 errors generated.

卡布姆。谁是对的?

【问题讨论】:

  • int function(int &value=value) 对我来说真的很奇怪。我将其更改为int function(int &value = ::value),因此它指的是全局value,而不是绑定到自身的引用。
  • @Eljay gcc 将其绑定到全局value 和int& value = value,但我认为按照当前标准是错误的。
  • 只是好奇-当您运行 gcc 时,本地值的值是多少? (哦,天哪,这个问题都错了)......
  • 从你可以在默认参数中使用decltype(param)的事实来看,我会说参数名称在范围内并且GCC是错误的,但这不是一个非常强大的基础。
  • @UKMonkey Apparently 是::value 的实际值,即引用不绑定到自身。

标签: c++ c++11 gcc clang language-lawyer


【解决方案1】:

我认为 clang 是正确的。来自basic.scope.pdecl:

名称的声明点紧跟在它的完整声明符(子句[dcl.decl])之后和它的初始化器(如果有的话)之前,除非下面提到。 [ 例子:

int x = 12;{ int x = x; }

这里第二个 x 用它自己的(不确定的)值初始化。 —结束示例]

另外,来自dcl.fct.default:

每次调用函数时都会评估默认参数。未指定函数参数的评估顺序。因此,函数的参数不应在默认参数中使用,即使它们没有被评估。在默认参数之前声明的函数的参数在范围内,可以隐藏命名空间和类成员名称

【讨论】:

  • 这看起来像是答案,很惊讶 gcc 错过了那个。
  • @SeanMcAllister,是的,令人惊讶的是 g++ 会错过这个。
  • 但是这个引用并没有禁止默认参数引用函数参数作为clang抱怨。
  • @VTT This one 会。
  • 唯一的用例是获取参数的地址来定义它自己的值。谁做过?为什么要让编码员在这种无用的情况下犯错误?标准是错误的,所以 gcc 是对的。
【解决方案2】:

由于 OP 将问题标记为 c++11,我检查了该标准的版本,并在 [basic.lookup.unqual] 子条款 11 中明确指出:

在查找用作默认参数 (8.3.6) 的名称期间 函数参数声明子句或用于 a 的表达式 构造函数(12.6.2)的mem-initializer,函数参数 名称是可见的并隐藏在 包含函数声明的块、类或命名空间范围。

因此,clang 是正确的。

【讨论】:

    【解决方案3】:

    Clang 在这里是正确的。首先将function's parameter scope 定义为:

    函数参数(包括出现在 lambda 声明符中的参数)或函数局部预定义变量 ([dcl.fct.def]) 具有函数参数范围。参数或函数局部预定义变量的潜在作用域从其声明点开始。[...]

    point of declaration 定义为

    名称的声明点紧跟在它的完整声明符之后和它的初始化器(如果有的话)之前,除非如下所述。 [ 示例:

    unsigned char x = 12;
    { unsigned char x = x; }
    

    这里第二个 x 用它自己的(不确定的)值初始化。 — 结束示例 ]

    所以value 应该是你刚刚声明的value,而不是来自全局空间的那个

    【讨论】:

      猜你喜欢
      • 2014-08-07
      • 2019-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      相关资源
      最近更新 更多