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

В C++1z будет введено "constexpr if" - в случае 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"?

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{});

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

Другие вопросы по тегам