Почему if constexpr не заставляет эту ошибку выражения постоянного константы исчезать?

Что касается этот вопрос. Ядро константное выражение, которое используется для инициализации 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).

30

Решение

Стандарт мало что говорит о отклоненное заявление из if constexpr, По сути, в [stmt.if] есть два утверждения об этом:

  1. Во вложенном шаблоне отброшенные операторы не создаются.
  2. Имена, на которые ссылаются из отклоненного оператора, не требуют определения ODR.

Ничто из этого не относится к вашему использованию: компиляторы вправе жаловаться на constexpr если инициализация. Обратите внимание, что вам нужно сделать условие зависимым от параметра шаблона, если вы хотите воспользоваться конкретизации потерпеть неудачу: если значение не зависит от параметра шаблона, сбой происходит, когда шаблон определенный. Например, этот код все еще не работает:

template <typename T>
void f() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}

Тем не менее, если вы делаете x зависит от типа T это нормально, даже когда f создается с int:

template <typename T>
void f() {
constexpr T x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}
int main() {
f<int>();
}
20

Другие решения

Обратите внимание, что для заявления, отбрасываемого Constexpr If:

выброшенное утверждение не может быть плохо сформировано для любой возможной специализации:

Чтобы устранить проблему, вы можете сделать заявление в зависимости от параметра шаблона, например,

template<typename T, int X> struct dependent_value { constexpr static int V = X; };

template <typename T>
void foo() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1 << dependent_value<T, x>::V;
}
}

ЖИТЬ

11

Я не уверен, почему вы ожидаете, что ветка не будет проверена. Единственный раз, когда ветвь if не проверяется, это когда она является частью шаблона, а не инстанцирован, согласно [stmt.if] p2:

Во время создания шаблона
Сущность (пункт 17), если условие не зависит от значения после его создания, отбрасываемое подзаголовок
(если есть) не был создан.

Ваш код, кажется, не в такой ситуации.

6
По вопросам рекламы [email protected]