我有一个小玩具程序:
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.
KABOOM。谁是对的?
答案 0 :(得分:32)
我认为铿锵是正确的。来自basic.scope.pdecl:
名称的声明点紧接在其完整的声明者(条款[dcl.decl])之后和初始化者之前(如果有的话),除非如下所述。 [例如:
int x = 12;{ int x = x; }
这里第二个x用它自己的(不确定的)值初始化。 - 结束例子]
此外,来自dcl.fct.default:
每次调用函数时都会计算默认参数。函数参数的评估顺序未指定。因此,函数的参数不应在默认参数中使用,即使它们未被评估。在默认参数之前声明的函数的参数在范围内,并且可以隐藏命名空间和类成员名称
答案 1 :(得分:18)
由于OP将问题标记为c ++ 11,我检查了该版本的标准,并在[basic.lookup.unqual]子条款11中明确指出:
在查找用作默认参数(8.3.6)的名称时 function parameter-declaration-clause或用于表达式 构造函数的mem-initializer(12.6.2),函数参数 名称是可见的,并隐藏在中声明的实体的名称 包含函数声明的块,类或命名空间范围。
因此,铿锵是正确的。
答案 2 :(得分:8)
Clang在这里是正确的。首先,function's parameter scope定义为:
函数参数(包括出现在lambda声明符中的函数)或函数本地预定义变量([dcl.fct.def])具有函数参数作用域。参数或函数本地预定义变量的潜在范围从其声明点开始。[...]
名称的声明点在其完整的声明者之后和初始化者之前(如果有的话),除非如下所述。 [实施例:
unsigned char x = 12; { unsigned char x = x; }
这里第二个x用它自己的(不确定的)值初始化。 - 结束例子]
因此value
应该是您刚刚声明的value
而不是全球空间中的const env