Специализация шаблонов против оптимизации компилятора

У меня есть класс с аргументом логического шаблона.

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, и ветвь, не принятая, будет отбрасываться во время компиляции.