Шаблоны функций Specialize против перегрузки функций и специализации классов - PullRequest
7 голосов
/ 15 июня 2009

Согласно этой статье от Херба Саттера, всегда следует выбирать Класс, специализирующийся более Перегрузка функции и определенно более Специализированные шаблоны функций,

Причина в том, что

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

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

Пример:

template <class T> void foo( T t);

Мы должны написать foo вот так, чтобы мы могли специализировать его на шаблонах классов, а не на специализации функций.

template<class T> 
struct FooImpl;

template <class T> void foo( T t) {
    FooImpl<T>::foo(t);
}

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

template<class U, class V> 
struct FooImpl< QMap< U, V > >;


Вот вопрос.

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

Уже есть несколько ссылок на статью GOTWCA, поэтому вы, должно быть, прочитали статью. Это означает, что инициаторы должны иметь дополнительную информацию, встаньте и просветите меня.

Ответы [ 4 ]

4 голосов
/ 15 июня 2009

Проблема с явной специализацией шаблона функции применима только в том случае, если функция также перегружена:

template <typename T> void foo (T*);   // #1

template <typename T> void foo (T);    // #2
template <> void foo<int*> (int*);

int main () {
  int * i;
  foo (i);  // Calls #1 not specialization of #2
}

Без перегрузки # 1 код будет работать как положено. Однако функция, которая вначале не перегружена, может иметь добавленные перегрузки, поскольку код сохраняется в будущем.

Это один из тех примеров, когда, хотя мне неприятно это говорить, у C ++ слишком много способов сделать то же самое. Лично, если вы обнаружите, что вам нужно специализировать шаблон функции, тогда мне нравится шаблон, предложенный TimW в его комментарии против ответа Нила Баттерворта , т.е. лучше всего сделать так, чтобы текущая функция отправляла вызов своего специализированного шаблона класса:

template <typename T> class DoFoo {
    static void do (T) { /* default behaviour */ }
};
template <> class DoFoo<int*> {
    static void do (int*) { /* int * behaviour */ }
};

template <typename T> void foo (T t)
{
  DoFoo<T>::do (t);
}

Если 'foo' перегружен, то, по крайней мере, разработчику понятнее, что эта функция не будет вызываться, т.е. разработчику не нужно быть гуру в области стандартов, чтобы знать, как правила специализации взаимодействуют с разрешением перегрузки.

В конечном счете, однако, код, сгенерированный компилятором, будет таким же, это просто проблема понимания кода со стороны разработчика.

3 голосов
/ 15 июня 2009

Вы предполагаете, что ТАК избиратели все гуру, а не они. За многие технически неправильные ответы проголосовали.

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

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

2 голосов
/ 15 июня 2009

Прежде всего, я не выговорщик (о чем бы вы ни говорили).

Голоса обычно не гарантируют правильность; есть даже немного неправильные ответы, которые были приняты, плюс положительные отзывы часто связаны со временем публикации конкретного ответа и т. д.

К вашей проблеме и статье: я прочитал статью, и я не вижу аргументов в пользу того, что вы предлагаете, чтобы это не относилось к перегрузке простой функции (шаблона). Трюк в основном делает то же самое, что и компилятор, если бы вы использовали специализации шаблонов функций (включая частичные, если они были разрешены), со всеми недостатками, о которых говорит Херб Саттер в статье. Поэтому я не думаю, что ваш путь «правильный» (по вашим словам), я просто считаю, что это уродливый способ достичь того, что вам не нужно.

Сравните:

Ваша частичная специализация:

template<class U, class V> 
struct FooImpl< QMap< U, V > >;

Функция перегрузки:

template<class U, class V> 
void foo(QMap< U, V > ) { ... }

и т.д.

Даже SFINAE возможен, частичное упорядочение функции (шаблона) следует почти тем же правилам, что и разрешение специализации шаблона ...

2 голосов
/ 15 июня 2009

Как указал Нейл, за наиболее правильные ответы проголосуют. И ответы уже наверху имеют тенденцию получать еще больше голосов в моем опыте.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...