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

"constexpr if" vs "if" с оптимизацией - зачем нужен "constexpr"?

С++ 1z представит "constexpr if" - если это будет иметь один из удаленных ветвей на основе условия. Кажется разумным и полезным.

Однако нельзя ли обойтись без ключевого слова constexpr? Я думаю, что во время компиляции компилятор должен знать, что условие зависания известно во время компиляции или нет. Если это так, даже самый базовый уровень оптимизации должен удалить ненужную ветвь.

Например (см. в godbolt: https://godbolt.org/g/IpY5y5):

int test() {
    const bool condition = true;
    if (condition) {
      return 0;
    } else {
      // optimized out even without "constexpr if"
      return 1;
    }
}

Исследователь Godbolt показывает, что даже gcc-4.4.7 с -O0 не скомпилировал "return 1", поэтому он достиг того, что было обещано с помощью constexpr if. Очевидно, такой старый компилятор не сможет это сделать, когда условие является результатом функции constexpr, но факт остается фактом: современный компилятор знает, является ли условие constexpr или нет, и мне не нужно явно указывать его.

Итак, вопрос:

Почему "constexpr" требуется в "constexpr if"?

4b9b3361

Ответ 1

Это легко объяснить на примере. Рассмотрим

struct Cat { void meow() { } };
struct Dog { void bark() { } };

и

template <typename T>
void pet(T x)
{
    if(std::is_same<T, Cat>{}){ x.meow(); }
    else if(std::is_same<T, Dog>{}){ x.bark(); }
}

Вызов

pet(Cat{});
pet(Dog{});

приведет к ошибке компиляции (пример wandbox), поскольку обе ветки оператора if должны быть хорошо сформированным.

prog.cc:10:40: error: no member named 'bark' in 'Cat'
    else if(std::is_same<T, Dog>{}){ x.bark(); }
                                     ~ ^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here
    pet(Cat{});
    ^
prog.cc:9:35: error: no member named 'meow' in 'Dog'
    if(std::is_same<T, Cat>{}){ x.meow(); }
                                ~ ^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here
    pet(Dog{});
    ^

Изменение pet для использования if constexpr

template <typename T>
void pet(T x)
{
    if constexpr(std::is_same<T, Cat>{}){ x.meow(); }
    else if constexpr(std::is_same<T, Dog>{}){ x.bark(); }
}

требуется только, чтобы ветки обрабатывались - только ветвь, соответствующая условию, должна быть хорошо сформирована (пример wandbox).

Отрывок

pet(Cat{});
pet(Dog{});

будет компилироваться и работать как ожидалось.