Что я должен делать вместо частичной специализации шаблонов функций?
Я хочу написать следующее:
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;
}