Что мне делать вместо частичной специализации шаблонов функций?


Я хочу написать следующее:

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 5

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;
}