Использование имени параметра внутри его собственного значения по умолчанию — законно ли это?

enum class E {
    One,
    Two
};

void foo(E value = decltype(value)::One) {
}

Его можно скомпилировать с помощью Clang (3.9), но нельзя скомпилировать с помощью GCC 6.1: value was not declared in this scope.

Какой компилятор правильный?


person vladon    schedule 09.11.2016    source источник
comment
Похоже, это ответ, но я не на 100% Конечно. Предоставление другим решать, следует ли закрыть его как обман.   -  person NathanOliver    schedule 09.11.2016
comment
@NathanOliver Этот вопрос касается доступа к значению параметра, что невозможно по уважительной причине (порядок оценки), но я ожидаю, что его имя и тип будут подчиняться другим правилам, поскольку эта причина не влияет на них.   -  person Quentin    schedule 09.11.2016
comment
@Quentin Вот почему я не голосовал за закрытие. Цитата из стандарта имеет Следовательно, параметры функции не должны использоваться в выражениях аргументов по умолчанию, даже если они не оцениваются. и я не уверен, применимо ли это здесь или нет.   -  person NathanOliver    schedule 09.11.2016
comment
@NathanOliver int h(int a, int b = sizeof(a)); используется в примере как ошибка, поэтому я бы сказал, что в конце концов это не разрешено.   -  person krzaq    schedule 09.11.2016
comment
@krzaq Нет, это прокомментировано хорошо   -  person Columbo    schedule 09.11.2016
comment
@NathanOliver Это не то же самое. Стандарт запрещает использование значений в потенциально оцениваемом выражении, но decltype(value) не является потенциально оцениваемым выражением.   -  person vladon    schedule 09.11.2016
comment
@Columbo интересно, в N4606 это прокомментировано как Ok, но ошибка в 4140.   -  person krzaq    schedule 09.11.2016
comment
Интересно, тогда это изменение языка с С++ 14 на С++ 17? Возможно, это был ДР. В С++ 14 это N3797 показывает, что использование sizeof(a) является незаконным.   -  person NathanOliver    schedule 09.11.2016


Ответы (1)


Согласно [basic.scope.pdecl]/1:

Точка объявления имени находится сразу после его полного декларатора (пункт 8) и перед его инициализатором (если есть), за исключением отмеченных. ниже.

Таким образом, параметр определенно объявлен в этой точке. Как насчет использования его в decltype? Формулировка устарела и непреднамеренно запретила это. См. основной вопрос 2082:

Согласно 8.3.6 [dcl.fct.default], параграф 9,

Аргумент по умолчанию оценивается каждый раз, когда функция вызывается без аргумента для соответствующего параметра. Порядок оценки аргументов функции не указан. Следовательно, параметры функции не должны использоваться в аргументе по умолчанию, даже если они не оцениваются. Это запрещает использование параметров в невычисленных операндах, например,

void foo(int a = decltype(a){});

Эта формулировка предшествует понятию «неоцененные операнды» (фраза «не оцененные» относится к вызовам функции, в которой предоставляется фактический аргумент, и поэтому аргумент по умолчанию не используется, а не к невычисленным операндам) и не должна применяться к таким случаям. .

Таким образом, цитируемый абзац был изменен следующим образом:

Параметр не должен появляться как потенциально вычисляемое выражение в аргументе по умолчанию.

Поскольку операнды decltype не оцениваются, теперь это нормально, а GCC неверен.

person Columbo    schedule 09.11.2016
comment
Это было введено только в проекте, но не в C++14. wg21.cmeerw.net/cwg/issue2082 - person vladon; 09.11.2016
comment
@vladon Да, я тоже это обнаружил после комментария krzaq. - person Columbo; 09.11.2016
comment
Действительно ли GCC неправильный или ему просто нужно обновить способ компиляции на С++ 17/1z? Похоже, это было запрещено в С++ 14, поэтому вы действительно не можете винить в этом GCC. - person NathanOliver; 09.11.2016
comment
@NathanOliver Да, можешь; устранение основных дефектов должно быть реализовано быстро, потому что они касаются фактических несоответствий в языке. Кроме того, какой смысл просто откладывать решение всех проблем до выпуска нового стандарта? - person Columbo; 10.11.2016