2015-03-05 4 views
26

Следующий фрагмент кода работает отлично в Clang 3.5, но не в GCC 4.9.2:Может ли constexpr сочетаться с изменчивым?

int main() 
{ 
    constexpr volatile int i = 5; 
} 

с ошибкой:

error: both 'volatile' and 'constexpr' cannot be used here

Если я осмотреть узел, который генерирует Clang, он показывает 5, как и ожидалось:

movl $5, -4(%rsp) 

В GCC, constexpr int i = 5 оптимизирован прочь, но volatile int i = 5 также показывает 5 в сборке. volatile const int i = 5 компилируется в обоих компиляторах. Это не внешняя концепция того, что что-то одновременно и волатильно, и const.

Какой компилятор соответствует стандартам?

+0

Что это вы пытаетесь выразить? Они по существу противоположны. Константа никогда не изменится, как только она будет установлена, но изменчивость почти гарантированно изменится (возможно, из другого потока). – TheBuzzSaw

+2

'constexpr' и' const' не то же самое –

+9

@TheBuzzSaw: 'volatile' не означает, что что-то имеет тенденцию к изменению. это просто означает, что доступ к памяти может иметь побочные эффекты, поэтому компилятор должен рассматривать его как I/O. Очень удобно использовать 'volatile' в системе, даже если значение гарантированно останется неизменным. – Mehrdad

ответ

23

Да, это верно, был defect report 1688: Volatile constexpr variables, который был подан на это, говоря:

There does not appear to be language in the current wording stating that constexpr cannot be applied to a variable of volatile-qualified type. Also, the wording in 5.19 [expr.const] paragraph 2 referring to “a non-volatile object defined with constexpr” might lead one to infer that the combination is permitted but that such a variable cannot appear in a constant expression. What is the intent?

он был отклонен а не дефект (NAD), ответ и обоснование было:

The combination is intentionally permitted and could be used in some circumstances to force constant initialization.

в ДР указывает такую ​​переменную сам по себе не годный к употреблению в постоянном выражении:

constexpr volatile int i = 5;  
constexpr int y = i ;   // Not valid since i is volatile 

Раздел [выраж.Уст]/2 включает в себя все случаи, что делает условное-выражение не является основной константой выражения, включая:

an lvalue-to-rvalue conversion (4.1) unless it is applied to

и все, за исключением требуют:

[...]that refers to a non-volatile [...] object [...]

+1

Я * знал * должен был быть DR, но не мог найти его. Отлично сработано. – Casey

17

Цитирование N4140 [dcl.constexpr]/9:

A constexpr specifier used in an object declaration declares the object as const . Such an object shall have literal type and shall be initialized.

Буквенного типа определен в [basic.types]/10:

A type is a literal type if it is:

(10.1) — void ; or

(10.2) — a scalar type; or

(10.3) — a reference type; or

(10.4) — an array of literal type; or

(10.5) — a class type (Clause 9) that has all of the following properties:

(10.5.1) — it has a trivial destructor,

(10.5.2) — it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and

(10.5.3) — all of its non-static data members and base classes are of non-volatile literal types.

Скалярного типа в пункте 9:

Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t , and cv-qualified versions of these types (3.9.3) are collectively called scalar types.

int является арифметическим, поэтому volatile int является скалярным типом и, следовательно, литералом. Таким образом, constexpr volatile int i = 5; является хорошо сформированной декларацией.

Интересно отметить, что выражение, которое оценивает i не может быть ядра-постоянная выражением, поскольку он применяет к именующему-Rvalue-преобразование в glvalue летучего типа ([expr.const]/2). Следовательно, выражения, которые оценивают i, не являются интегральными постоянными выражениями или постоянные выражения. Я не уверен, что constexpr в этой декларации имеет какой-либо эффект, за исключением того, что i неявно const и (отклик к @T.C.), требующий, чтобы его инициализатор являлся постоянным выражением.

Я сообщил об этом как GCC bug 65327, посмотрим, что скажут люди GCC.

2015-03-16 Обновление: исправлена ​​ошибка для GCC 5.

+0

Наличие «нелетучих» в (10.5.3) говорит мне, что, по крайней мере, несколько вероятно, что стандарт означает исключение волатильно-квалифицированных типов в целом, и это позволяет контролировать ситуацию. – Hurkyl

+4

«Я не уверен, что constexpr в этой декларации имеет какой-либо эффект, за исключением того, что я неявно const». - Он все еще ограничивает инициализатор постоянным выражением. –

+0

Для чего это стоит, вот [patch] (http://patchwork.ozlabs.org/patch/173189/), который ввел эту ошибку. Тестирование по wandbox показывает, что ошибка была введена между 4.5.4 и 4.6.4. – user4637702

Смежные вопросы