Можно ли предположить, что компилятор при оценке if constexpr
полностью отбрасывает неподтвержденное условие и генерирует код только для ветви, которая удовлетворяет условию if constexpr
? Стандарт определяет такое поведение для компилятора?
Стандарт определяет, что с [stmt.if] :
Если оператор if
имеет форму if constexpr
, значение условия должно быть контекстно-преобразованным константным выражением типа bool
; эта форма называется constexpr, если оператор. Если значение преобразованного условия равно false
, первое подзаголовок является оператором отбрасывания, в противном случае второе подзаголовок, если оно присутствует, является оператором отбрасывания. Во время создания экземпляра вмещающего шаблонного объекта, если условие не зависит от значения после его создания, отброшенное подсостояние (если оно есть) не создается.
Суть в том, что оператор отбрасывания не создан - это основная цель if constexpr
как языковой функции, позволяющая вам написать:
template <typename T0, typename... T>
void print_ifconstexpr(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
if constexpr (sizeof...(T) > 0) {
print_ifconstexpr(std::forward<T>(rest)...);
}
}
Вы не можете сделать это с помощью простого if
, потому что это все равно потребует создания экземпляров подстановок - даже если условие может быть определено как false
во время компиляции. Для простого if
потребуется возможность звонить print_ifconstexpr()
.
if constexpr
не будет создавать рекурсивный вызов, если в rest...
нет чего-то, так что это работает.
Все остальное вытекает из отсутствия реализации. Не может быть никакого сгенерированного кода для отклоненного оператора.
Форма if constexpr
легче написать, легче понять и, несомненно, быстрее компилируется. Определенно предпочитаю это.
<ч />
Обратите внимание, что вашему первому примеру вообще не нужен SFINAE. Это работает просто отлично:
template <typename T>
void print(T&& x)
{
std::cout << x << std::endl;
}
template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print(std::forward<T>(rest)...);
}
Как и:
void print() { }
template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print(std::forward<T>(rest)...);
}