constexpr препратка към неконстантен обект

Разрешено ли е да се декларира неконстантна препратка като constexpr? Примерен код:

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

Това се приема от gcc и clang (пробвах няколко текущи и минали версии и на двете, обратно към C++11, и всички го приеха). Въпреки това мисля, че не трябва да се приема, защото C++14 [dcl.constexpr/9] казва:

ако в референтна декларация се използва спецификатор constexpr, всеки пълен израз, който се появява в неговия инициализатор, трябва да бъде постоянен израз

и x не е постоянен израз.

Езикът в най-новата чернова на C++17 на [dcl.constexpr] се промени и дори вече не споменава изрично 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 към rvalue, освен ако не се прилага към [случаи, които този код прави' т съвпада]   -  person M.M    schedule 21.04.2017
comment
x е присвоена литерална стойност, не трябва ли това да е достатъчно добро за компилатора, за да знае, че времето за компилиране е известно?   -  person asimes    schedule 21.04.2017
comment
Как оценяването на израза x налага преобразуване от lvalue към 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 към 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