Подтвердить что ты не робот

Спецификация шаблона Функция перегрузки функций VS

В учебнике у меня есть заметки о том, что вы можете предоставить свою собственную реализацию для стандартных функций библиотеки, таких как swap(x,y) через специализированную специализацию для перегрузки функций. Это было бы полезно для любых типов, которые могут извлечь выгоду из чего-то иного, чем переопределение присваивания, например, STL containers (у которых уже есть свопы, я знаю).

Мои вопросы:

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

  • Почему это лучше? Или, если они равны, почему это?

4b9b3361

Ответ 1

Рассказ: перегрузите, когда сможете, специализируйтесь, когда вам нужно.

Длинная история: С++ рассматривает специализацию и перегрузки по-разному. Это лучше всего объяснить с помощью примера.

template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <>           void foo<int>(int*); // specialisation of foo(T*)

foo(new int); // calls foo<int>(int*);

Теперь замените последние два.

template <typename T> void foo(T);
template <>           void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)

foo(new int); // calls foo(T*) !!!

Компилятор выполняет перегрузку, прежде чем он даже посмотрит на специализации. Таким образом, в обоих случаях разрешение перегрузки выбирает foo(T*). Однако только в первом случае он находит foo<int*>(int*), потому что во втором случае специализация int* является специализацией foo(T), а не foo(T*).


Вы упомянули std::swap. Это усложняет ситуацию.

В стандарте говорится, что вы можете добавлять специализации в пространство имен std. Отлично, так что у вас есть тип Foo, и у него есть своя команда, тогда вы просто специализируете swap(Foo&, Foo&) в пространстве имен std. Нет проблем.

Но что, если Foo - это шаблонный класс? С++ не имеет частичной специализации функций, поэтому вы не можете специализировать swap. Ваш единственный выбор - перегрузка, но стандарт говорит, что вам не разрешено добавлять перегрузки в пространство имен std!

На данный момент у вас есть два варианта:

  • Создайте функцию swap(Foo<T>&, Foo<T>&) в своем собственном пространстве имен и надейтесь, что она будет найдена через ADL. Я говорю "надеюсь", потому что, если стандартная библиотека вызывает swap как std::swap(a, b);, то ADL просто не будет работать.

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

Одна вещь, которую следует помнить, заключается в том, что нет гарантии, что стандартная библиотека вообще использует swap. Большинство алгоритмов используют std::iter_swap и в некоторых реализациях, на которые я смотрел, он не всегда пересылает std::swap.

Ответ 2

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

например.

template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }

Чтобы сделать что-то подобное с помощью перегрузки функций, вам нужно добавить параметр к сигнатуре функции:

int zero(int) { return 0; }
long zero(long) { return 0L; }

Ответ 3

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

Другой вариант заключается в том, чтобы поместить вашу функцию swap в то же пространство имен, что и работа, на которой она работает, и using std::swap; перед вызовом неквалифицированной замены.