Что касается этого вопроса. Выражение основной константы, которое используется для инициализации constexpr
переменной y
, имеет неправильный формат. Так много дано.
Но если я попытаюсь превратить if
в if constexpr
:
template <typename T>
void foo() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1 << x;
}
}
int main(){
foo<int>();
}
Ошибка сохраняется. С GCC 7.2 все еще дает:
error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]
Но я подумал, что на заброшенной ветке семантическую проверку нужно оставить непревзойденной.
Однако косвенное обращение через constexpr
лямбда действительно помогает:
template <typename T>
void foo(){
constexpr int x = -1;
constexpr auto p = []() constexpr { return x; };
if constexpr (x >= 0){
constexpr int y = 1<<p();
}
}
Спецификатор constexpr
на y
, похоже, меняет способ проверки отброшенной ветви. Это предполагаемое поведение?
@ max66 был достаточно любезен, чтобы проверить другие реализации. Он сообщает, что ошибка воспроизводится как с GCC (7.2.0 / Head 8.0.0), так и с Clang (5.0.0 / Head 6.0.0).
constexpr
(просто определяя int y = 1 ‹< x; я больше не вижу ошибок (я полагаю, что это правильно, еслиy
- инициализированная среда выполнения), но я вижу предупреждение (неиспользуемая переменнаяy
); поэтому (если я не ошибаюсь) эта ветвь скомпилирована. Или, лучше, я думаю, что это правильно в том смысле, что сconstexpr
y
инициализируется время компиляции (так1 << x
немедленно проверяется), а без инициализируется время выполнения. - person max66   schedule 01.10.2017int y = 1 << x;
- это просто неопределенное поведение. Добавлениеconstexpr
делает его некорректным, потому что UB не допускается в постоянном выражении. - person Oktalist   schedule 01.10.2017