2016-12-05 5 views
28

C++ 1z представит «constexpr if» - если это будет иметь один из удаленных ветвей, основанный на условии. Кажется разумным и полезным."constexpr if" vs "if" с оптимизацией - зачем нужен "constexpr"?

Однако невозможно ли исключить ключевое слово 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 EXPLORER показывает, что даже GCC-4.4.7 с -O0 не компилировать "возвращает 1", так что он достиг того, что было обещано, с constexpr if. Очевидно, такой старый компилятор не сможет это сделать, когда условие является результатом функции constexpr, но факт остается фактом: современный компилятор знает, является ли условие constexpr или нет, и мне не нужно явно указывать его.

Так что вопрос:

Почему "constexpr" необходим "constexpr если"?

+7

Это не только вопрос оптимизации: мертвая ветвь 'constexpr if' допускается быть недействительной, то есть она не будет компилироваться сама по себе. Ваш вопрос стоит. – Quentin

ответ

38

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

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 example), потому что обе ветви 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 example).

Сниппет

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

будет собирать и работать, как ожидалось.

+1

Спасибо. Различие между «синтаксическим» и «хорошо сформированным» ускользало от меня раньше :-) – MateuszL