constexpr ссылка на неконстантный объект

Разрешено ли объявить неконстантную ссылку как constexpr? Пример кода:

int x = 1;
constexpr int& r = x;

Это принимается gcc и clang (я пробовал несколько текущих и прошлых версий обеих, вернувшись к C ++ 11, и все приняли это). Однако я думаю, что это не следует принимать, потому что C ++ 14 [dcl.constexpr / 9] говорит:

если спецификатор constexpr используется в объявлении ссылки, каждое полное выражение, которое появляется в его инициализаторе, должно быть постоянным выражением

и x не является постоянным выражением.

Язык в последнем проекте [dcl.constexpr] на C ++ 17 изменился и даже не упоминает constexpr ссылки явно, я не могу понять, что он пытается сказать о них.


person M.M    schedule 21.04.2017    source источник
comment
Кто сказал, что x не является постоянным выражением?   -  person T.C.    schedule 21.04.2017
comment
x не является основным постоянным выражением {{требуется цитирование}}   -  person T.C.    schedule 21.04.2017
comment
@ T.C. [expr.const] / 2 e является основным константным выражением, если оценка e не будет оценивать одно из следующего: [...] преобразование lvalue-to-rvalue, если оно не применяется к [случаям, когда этот код не ' т совпадение]   -  person M.M    schedule 21.04.2017
comment
x присваивается буквальное значение, разве этого не должно быть достаточно для компилятора, чтобы знать, что время компиляции известно?   -  person asimes    schedule 21.04.2017
comment
Как для вычисления выражения x требуется преобразование lvalue-to-rvalue?   -  person T.C.    schedule 21.04.2017
comment
@ T.C. Я думал, это подразумевалось, что это было ... видимо, нет. Таким образом, x вместо этого будет охватываться /2.9, что, как я предполагаю, предназначено для того, чтобы сказать, что выражение id, обозначающее объект, является постоянным выражением, если оно было инициализировано постоянным выражением. Мне не ясно, означает ли это предложение (переменную) или (элемент данных ссылочного типа), или (переменную или элемент данных) ссылочного типа   -  person M.M    schedule 21.04.2017
comment
Последнее, конечно. Прежде чем углубляться в сложные правила C ++ 1 *, помните, что это всегда было правильным: int x; template<int&> struct C {}; C<x> c; Что-то, что может использоваться в качестве аргумента шаблона, должно быть постоянным выражением.   -  person T.C.    schedule 21.04.2017


Ответы (1)


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

Если вы используете x в контексте, который требует prvalue, что приводит к применению к нему преобразования lvalue-to-rvalue, то результирующее выражение prvalue - назовите его TO_RVALUE(x) - не будет постоянным выражением по очевидным причинам. Но в случае привязки ссылок такого преобразования нет.

person T.C.    schedule 21.04.2017
comment
Это зависит от инициализатора? (Например, int x = rand(); по-прежнему делает x постоянным выражением?) - person M.M; 21.04.2017
comment
@ M.M Нет. (Да.) Постоянное выражение lvalue просто обозначает объект (в основном, это как его адрес). То, чем он инициализируется, не имеет значения, и его даже не нужно знать компилятору (например, достаточно extern int x;). - person T.C.; 21.04.2017