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

Одна специализированная специализация для нескольких классов

Предположим, что у нас есть шаблонная функция "foo":

template<class T>
void foo(T arg)
{ ... }

Я могу сделать специализацию для определенного типа, например.

template<>
void foo(int arg)
{ ... }

Если бы я хотел использовать ту же специализацию для всех встроенных числовых типов (int, float, double и т.д.), я бы писал эти строки много раз. Я знаю, что тело может быть выброшено в другую функцию, и просто вызвать это должно быть сделано в каждом специализированном органе, однако было бы лучше, если бы я мог избежать наложения этого "void foo (..." для каждого типа. любая возможность сообщить компилятору, что я хочу использовать эту специализацию для всех этих типов?

4b9b3361

Ответ 1

Вы можете использовать std::numeric_limits, чтобы узнать, является ли тип числовым (is_specialized является истинным для всех типов с плавающей и целочисленной базой).

// small utility
template<bool> struct bool2type { };

// numeric
template<typename T>
void fooImpl(T arg, bool2type<true>) {

}

// not numeric
template<typename T>
void fooImpl(T arg, bool2type<false>) {

}

template<class T>
void foo(T arg)
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); }

Ответ 2

Вы можете использовать подход с препроцессором.

foo.inc:

template<>
void foo(TYPE arg)
{ /* do something for int, double, etc. */ }

foo.h:

template<class T>
void foo(T arg)
{ /*do something */ }

#define TYPE int
#include "foo.inc"
#undef TYPE

#define TYPE double
#include "foo.inc"
#undef TYPE

и др.

Ответ 3

С boost:

#include <boost/type_traits/is_scalar.hpp>
#include <iostream>
#include <string>

namespace detail
{
    typedef const boost::true_type& true_tag;
    typedef const boost::false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, boost::is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}

В большинстве случаев вы можете легко сделать это без повышения:

#include <iostream>
#include <string>

// boolean stuff
template <bool B>
struct bool_type {};

typedef bool_type<true> true_type;
typedef bool_type<false> false_type;

// trait stuff
template <typename T>
struct is_scalar : false_type
{
    static const bool value = false;
};

#define IS_SCALAR(x) template <> \
            struct is_scalar<x> : true_type \
            { \
                static const bool value = true; \
            };

IS_SCALAR(int)
IS_SCALAR(unsigned)
IS_SCALAR(float)
IS_SCALAR(double)
// and so on

namespace detail
{
    typedef const true_type& true_tag;
    typedef const false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}

Ответ 4

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

Ответ 5

Вы можете написать небольшой script (например, Perl), чтобы сгенерировать исходный файл для вас. Создайте массив, содержащий все типы, которые вы хотите специализировать, и запишите для каждого из них заголовок функции. Вы даже можете встраивать выполнение script в свой файл makefile, чтобы автоматически его запустить, если вы что-то изменили.

Примечание: предполагается, что реализация foo может быть сделана тривиальной и схожий для каждого типа, например, просто вызывая реальную функцию реализации. Но это позволяет избежать кучи шаблона/препроцессора mumbo-jumbo, который может заставить будущего сопровождающего поцарапать ему голову.