Подтвердить что ты не робот

Почему 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 lambda действительно помогает:

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).

4b9b3361

Ответ 1

В стандарте не говорится об отброшенном утверждении if constexpr. В [stmt.if] есть по существу два утверждения:

  • В прилагаемом шаблоне отбрасываемые операторы не создаются.
  • Имена, на которые ссылаются от отброшенного оператора, не требуются. 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>();
}

Ответ 2

Обратите внимание, что для оператора, отбрасываемого 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;
    }
}

LIVE

Ответ 3

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

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

Ваш код, похоже, не в ситуации, когда это применимо.