Специализация шаблонов против оптимизации компилятора
У меня есть класс с аргументом логического шаблона.
template<bool b>
class Foo {
void doFoo();
};
Я хочу, чтобы doFoo
делал разные вещи, основываясь на значении b
.
Наивно я мог написать
Опция 1
template<bool b> void Foo<b>::doFoo() {
if (b) cout << "hello";
else cout << "goodbye";
}
Это кажется мне неэффективным, потому что я должен выполнить if
каждый раз функция называется событием, хотя правильная ветка должна быть известна во время компиляции. Я мог бы исправить это с помощью специализации шаблона:
Вариант 2
template<> void Foo<true>::doFoo() { cout << "hello"; }
template<> void Foo<false>::doFoo() { cout << "goodbye"; }
Таким образом, у меня нет каких-либо условностей, выполняемых во время выполнения. Это решение немного сложнее (тем более, что в моем реальном коде класс имеет несколько аргументов шаблона, и вы не можете частично специализировать функции, поэтому мне нужно будет обернуть функцию в классе).
Мой вопрос заключается в том, что компилятор достаточно умен, чтобы знать, что он не выполняет условие в варианте 1, поскольку он всегда выполняется одинаково или мне нужно написать специализации? Если компилятор достаточно умен, я был бы рад узнать, зависит ли это от компилятора или от языковой функции, на которую я могу положиться?
Ответы
Ответ 1
Компилятор, вероятно, оптимизирует ветвь, так как во время компиляции известно, что такое b
. Это не гарантируется, и единственный способ узнать наверняка - проверить сборку.
Если вы можете использовать С++ 17, вы можете использовать if constexpr
и гарантировать, что будет существовать только одна ветвь.
Ответ 2
Это кажется мне неэффективным, потому что я должен выполнить if, если каждый раз, когда функция вызывается
Компилятор, вероятно, оптимизирует это, но это не гарантируется стандартом. Чтобы быть уверенным, вы должны посмотреть на вывод компилятора, о котором вы заботитесь (с помощью параметров компиляции, которые вы планируете использовать): например. clang не имеет ветки в связанном примере (у не оптимизированной версии есть много шаблонов вызова функций, но нет ветки).
В С++ 17 вы можете использовать if constexpr
, и ветвь, не принятая, будет отбрасываться во время компиляции.