2015-12-20 2 views
7

Но он компилируется в gcc 4.9.0. См live example:Насколько я могу судить, этот код не должен компилироваться, согласно §5.19/3 и §5.19/2 в C++ 14

#include <iostream> 
struct A { 
    constexpr A(): i(5) {} 
    int&& f() { return std::move(i); } 
    int i; 
} a; 

A&& f(A& a) { return std::move(a); } 

int main() { 
    A a; 
    int b[a.f()]{ 0, 1, 2, 3, 4 }; 
    std::cout << b[4] << '\n'; 
} 

От §5.19/3 имеет:

Неотъемлемой константой является выражение интеграла или незаданного перечислимого типа, неявно преобразуется в prvalue, где преобразованные выражение представляет собой основное константное выражение. [Примечание: такие выражения могут использоваться в качестве границ массива (8.3.4, 5.3.4) в качестве битового поля длин (9.6) в качестве инициализаторов перечислителя, если базовый тип не является фиксированным (7.2), а в качестве выравниваний (7.6.2). Примечание]

Выражение a.f() является выражением целочисленного типа. Мне кажется (хотя мне нужно разъяснение по этому вопросу), что это выражение также можно преобразовать в prvalue, потому что это значение x. Но я думаю, что настоящая проблема здесь заключается в том, что выражение a.f() равно не выражение константы ядра, так как оно удовлетворяет точке пули (2.1) в п. 5.19/2.

§5.19/2:

Условное выражение e является одним из основных константа если только оценки e, следуя правилам абстрактной машины (1.9), бы оценить одно из следующих действий выражения:

(2.1) - this (5.1.1), за исключением в constexpr функции или конструктора в constexpr, который оценивается как часть e;

+1

Если вы попробуете скомпилировать это с помощью clang ++, он указывает, что «массивы переменных размеров не разрешены» - поэтому у меня такое чувство, что gcc просто недостаточно педантичен. –

+0

Убедительный GCC для обеспечения соответствия может быть болью. Я обнаружил, что компиляция с флагом '--pedantic-errors', похоже, делает трюк. Я бы предпочел строгое соответствие по умолчанию и флаги, чтобы отключить его. – Galik

+0

Включает ли этот сайт режим строгой совместимости в компиляторе (я слишком ленив, чтобы выяснить, какие сценарии/сторонние сайты позволяют увидеть его для себя)? В противном случае причина в том, что g ++ имеет нестандартное расширение для массивов продолжительности хранения с не постоянным размером. – celtschk

ответ

7

Вы правы, a.f() не является постоянным выражением. А массивы переменной длины не допускаются стандартом C++. Однако компилятор GNU поддерживает их как language extension. Вы можете попросить компилятор дать вам предупреждение при использовании нестандартных расширений с -pedantic option или с ошибкой -pedantic-errors.

Редакция: По-видимому, GCC 4.9 added официальная поддержка N3639, предложение добавить массивы переменной длины в стандарт C++ 14. В итоге предложение не было включено в стандарт, но GCC 4.9 был выпущен до C++ 14, так что изменения не были отражены. Таким образом, VLA поддерживаются GCC 4.9 специально в режиме C++ 14, и вышеуказанные параметры не отключают их. Обратите внимание, что режим C++ 14 все еще экспериментальный (даже в GCC 5).

+0

Нет сообщений об ошибках с '-pedantic-errors', а также предупреждениями с' -pedantic' – Ayrosa

+0

Вы бы сказали, что это также массив переменной длины? 'struct A {operator int() {return 5; }} a; int main() {int b [a] {0, 1, 2, 3, 4}; } ' – Ayrosa

+1

@ Айроса хмм, я попробовал, и, по-видимому, нет никакого предупреждения/ошибки при компиляции с' -std = C++ 14' с использованием g ++ - 4.9.2, но есть, когда скомпилирован с '-std = c + + 11'. Предупреждение работает в C++ 14 с g ++ - 5.2.0. Это может быть ошибка компилятора и, по-видимому, исправлена. – user2079303

2

Следующего нестандартный код

int x = std::rand(); 
int r[x] = { 1,2,3 }; 

компилирует под г ++ не потому, что g++ ошибочно воспринимает std::rand() как постоянное выражение, а потому, что она реализует VLAS по умолчанию. Используйте -pedantic или -Wvla, чтобы предупредить о них, -Werror=vla, чтобы превратить эти предупреждения в ошибки.

+1

Однако ошибка не отображается, когда я использую '-pedantic' в моем коде выше. – Ayrosa

+1

@Ayrosa Возможно, это потому, что 4.9 относительно старый. Это показано в 5.2. –

+0

Если я изменил функцию 'f' как' constexpr' в моем коде выше, '5.2 'все еще показывает ошибку, но теперь я считаю, что код является законным из-за §5.19/2 и §5.19/3. – Ayrosa