Что мне делать вместо частичной специализации шаблонов функций?
Я хочу написать следующее:
template <typename S, typename T> void foo() {
/* code for the general case */
}
template <typename T> void foo<MySType,T>() {
/* partially specialized code - for any kind of T, but when S is MySType */
}
Или, в других случаях, следующее:
template <typename S, typename T> void bar(const S& a, const T& b) {
/* code for the general case */
}
template <typename T> void bar<MySType,T>(const MySType& a, const T& b) {
/* partially specialized code - for any kind of T, but when S is MySType */
}
C++(11) не позволит мне сделать это.
Теперь я читаю этот вопрос и его ответы; предположим, я покупаю объяснение, почему у нас нет частичной специализации шаблона (или просто предполагаю, что я живу в реальности и действительно хочу писать код). Ну, а что делаю я вместо этого?
Я бы предпочел не заключать эти функции в класс, если только это мое последнее средство.
3 ответа:
Другой вариант-использовать шаблон вспомогательного класса, где вы Можете сделать частичную специализацию и скрыть ее с помощью функции-оболочки, которая сама по себе не нуждается в частичной специализации:
#include <iostream> template<typename S, typename T> struct foo_helper { void foo() { std::cout << "general func" << std::endl; } }; struct MyType {}; template <typename T> struct foo_helper <MyType,T> { void foo() { std::cout << "partially specialized code - for any kind of T, but when S is MyType" << std::endl; } }; template<typename S, typename T> void foo() { foo_helper<S, T>().foo(); } int main () { foo<int, int>(); foo<int, double>(); foo<MyType, long>(); }
Это также допустимо для C++98/03.
Перегрузка! Перегрузка во всех отношениях превосходит специализацию. Часть разрешения перегрузки-это выбор наиболее специализированной перегрузки. Просто объявите "специализации" как перегрузки, и это будет работать, если частичная специализация будет иметь.
Однако избегайте явных аргументов шаблона. Вместо этого можно использовать диспетчеризацию тегов.template< typename t > struct tag {}; template <typename S, typename T> foo( tag<S>, tag<T> ) { /* code for the general case */ } template <typename T> foo( tag<MyType>, tag<T> ) { /* partially specialized code - for any kind of T, but when S is MyType */ }
Поскольку теги пусты и передаются по значению, их вклад в накладные расходы на вызов функции может быть исключен компилятором.
Вы можете частично специализировать вспомогательную структуру:
#include <iostream> namespace Detail { template <typename S, typename T> struct Foo { static void apply() { std::cout << "general case\n"; } }; template <typename T> struct Foo<int, T> { static void apply() { std::cout << "specialized code\n"; } }; } template <typename S, typename T> void foo() { Detail::Foo<S, T>::apply(); } int main() { foo<double, double>(); foo<int, double>(); return 0; }