Специализация шаблона или условные выражения?

Я глубоко погрузился в новый проект, к которому обращаюсь с кучей шаблонов и их специализаций. Теперь, после дня без программирования, я задаюсь вопросом, действительно ли это стоит дополнительных строк кода.

Вопрос: в чем преимущества специализации?

Это:

template <int i> class A {};
template <> class A <1> { void foo() {/* something */}  };
template <> class A <2> { void foo() {/* something else*/}  };
template <> class A <3> { void foo() {/* even different*/}  };

В любом случае лучше (более быстрое выполнение), чем

template <int i> class A { 
   void foo() {
      if (i==1) {/* something */}
      else if (i==2) {/* something else*/}
      else if (i==3) {/* even different*/}
   }
};

?

Редактировать:

Код является частью библиотеки, которую могут использовать другие. Я использую gcc 4.6.3, но в итоге код будет использоваться с разными компиляторами.

Редактировать:

Эти два фрагмента кода приводят к созданию идентичных двоичных файлов с использованием gcc 4.6.3. Я не могу протестировать весь случай, так как мой фактический код далек от использования. Это действительно кажется вопросом принципа, универсальности, возможности повторного использования, удобства обслуживания и т. Д.


person steffen    schedule 01.07.2012    source источник
comment
Это зависит от вашего компилятора, но я предполагаю, что обычно он компилируется в эквивалентный код.   -  person Vaughn Cato    schedule 01.07.2012
comment
Вы хотя бы профилировали сначала, прежде чем задавать этот вопрос?   -  person Axel Gneiting    schedule 01.07.2012
comment
@Axel Gneiting: Что заставляет вас думать, что это вообще связано с производительностью и/или профилированием?   -  person AnT    schedule 01.07.2012
comment
@Andrey: Никак лучше (быстрее исполнение)   -  person    schedule 02.07.2012


Ответы (4)


Здесь главное не скорость, а расширяемость.

Преимущество специализации состоит в том, что клиентам вашего кода будет проще добавлять новые перегрузки foo(). Предположим, позже вы решите добавить новое поведение для i=4: в первом подходе вы просто добавляете новую специализацию; во второй версии нужно модифицировать функцию foo(). Если вы выпустили свою библиотеку в бинарном виде, клиенты будут недовольны.

Предпочтение подхода специализации второму является проявлением принципа открытости/закрытости: код должен быть открыт для расширения, закрыт для модификации.

person TemplateRex    schedule 01.07.2012

Это зависит от используемого компилятора. Я сам часто пишу такой код, и мой компилятор делает все правильно за меня. Однако, поскольку ничто в стандарте C++ не требует от компиляторов сообразительности в этом отношении, у вас могут возникнуть проблемы. Поэтому убедитесь, что ваш компилятор работает правильно. Как правило, не полагайтесь на эту функцию, если вы пишете повторно используемую библиотеку, предназначенную для использования кем-то другим, если вы планируете портировать этот код на другие компиляторы и/или экзотические среды и т. д.

person Community    schedule 01.07.2012
comment
@steffen: точно, специализация - это путь - гарантированно работает по всем направлениям, проще в обслуживании и т. Д. Но только если вам это действительно нужно. Как уже упоминалось, в вашем случае вам может быть лучше с if-else и/или переключателем. - person ; 02.07.2012

Вы спрашиваете: «Почему специализация по шаблону лучше», но позвольте мне сказать, почему она хуже. Я предполагаю, что по крайней мере часть кода для i=1, i=2 и i=3 является общим (иначе, почему у него одинаковое имя?). Если это так, вам, возможно, придется дублировать некоторый код, когда вы переходите к специализации, и это затрудняет поддержку кода.

Дублирование кода лучше предоставить компилятору, который довольно хорошо справляется с этими конструкциями if-elseif-else. Вы даже можете иметь if (i<3), что было бы очень неудобно реализовать со специализацией.

Конечно, если ваши функции почти полностью различаются, вы не получаете этого недостатка при использовании шаблонной специализации (и получаете преимущества).

person anatolyg    schedule 01.07.2012

Иногда невозможно написать код как одну функцию, потому что код, допустимый для i=1, может быть недействителен для i=2, и даже если он никогда не выполняется, компилятор давится!

Например:

template <int i> class A { 
   void foo() {
      if (i==1)
      {
          cout << "Easy";
      }
      else if (i==2)
      {
          int stuff[100 * i - 110] = {42}; // error: negative array size for i=1
          cout << stuff[0];
      }
      else if (i==3)
      {
          /* even different*/
      }
   }
};
person anatolyg    schedule 01.07.2012