Является ли gcc или clang правильной об этом поведении?
У меня есть небольшая игрушечная программа:
static int value = 0;
int function(int &value=value) {
return value;
}
int main() {
function();
}
Компиляция с g++ 7.2:
g++ -std = С++ 11 -Wall -Wextra test.cc -o test
Нет проблем.
Компиляция с кланом g++ -3.9:
clan g++ -3.9 -std = С++ 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. Кто прав?
Ответы
Ответ 1
Я думаю, что clang правильный. Из basic.scope.pdecl:
Точка объявления для имени сразу же после его полного объявления (Clause [dcl.decl]) и перед его инициализатором (если есть), кроме как указано ниже. [ Пример:
int x = 12;{ int x = x; }
Здесь второй x инициализируется собственным (неопределенным) значением. - конец примера]
Кроме того, из dcl.fct.default:
Аргументы по умолчанию оцениваются каждый раз при вызове функции. Порядок оценки аргументов функции не указан. Следовательно, параметры функции не должны использоваться в аргументе по умолчанию, даже если они не оцениваются. Параметры функции, объявленной до аргумента по умолчанию, находятся в области видимости и могут скрыть пространства имен и имена членов класса
Ответ 2
Поскольку OP помечен как С++ 11, я проверил эту версию стандарта и в подпункте 11 [basic.lookup.unqual], в котором явно указано, что:
Во время поиска имени, используемого в качестве аргумента по умолчанию (8.3.6) в объявлении функции-объявления-предложения или используемого в выражении mem-initializer для конструктора (12.6.2), имена параметров функции видны и скрыть имена объектов, объявленных в блоках, классах или пространствах пространства имен, содержащих объявление функции.
Таким образом, clang является правильным.
Ответ 3
Клэнг здесь прав. Сначала область параметров функции определяется как:
Параметр функции (включая один, который появляется в лямбда-деклараторе) или функционально-локальная предопределенная переменная ([dcl.fct.def]) имеет область параметров функции. Потенциальная область параметра или локальная предопределенная переменная функции начинается с момента ее объявления. [...]
и точка объявления определяется как
Точка объявления для имени сразу же после его полного декларатора и перед его инициализатором (если есть), за исключением случаев, указанных ниже. [ Пример:
unsigned char x = 12;
{ unsigned char x = x; }
Здесь второй x инициализируется собственным (неопределенным) значением. - конец примера]
Таким образом, value
должно быть value
вы только что объявили, а не тем из глобального пространства