Как я могу написать шаблон функции для всех типов с определенной чертой типа? - PullRequest
7 голосов
/ 29 марта 2010

Рассмотрим следующий пример:

struct Scanner
{
    template <typename T>
    T get();
};

template <>
string Scanner::get()
{
    return string("string");
}

template <>
int Scanner::get()
{
    return 10;
}

int main()
{
    Scanner scanner;
    string s = scanner.get<string>();
    int i = scanner.get<int>();
}

Класс Scanner используется для извлечения токенов из некоторого источника. Приведенный выше код работает нормально, но не удается, когда я пытаюсь get других целочисленных типов, таких как char или unsigned int. Код для чтения этих типов точно такой же, как код для чтения int. Я мог бы просто продублировать код для всех других целочисленных типов, которые я хотел бы прочитать, но я бы лучше определил один шаблон функции для всех целочисленных типов.

Я пробовал следующее:

struct Scanner
{
    template <typename T>
    typename enable_if<boost::is_integral<T>, T>::type get();
};

Это работает как заклинание, но я не уверен, как заставить Scanner::get<string>() снова работать. Итак, как я могу написать код, чтобы я мог делать scanner.get<string>() и scanner.get<any integral type>() и иметь одно определение для чтения всех целочисленных типов?

Обновление: бонусный вопрос : Что делать, если я хочу принять более одного диапазона классов на основе некоторых черт? Например: как мне подходить к этой проблеме, если я хочу иметь три get функции, которые принимают (i) целочисленные типы (ii) типы с плавающей запятой (iii) строки, соответственно.

Ответы [ 2 ]

10 голосов
/ 29 марта 2010
struct Scanner
{
    template <typename T>
    typename boost::enable_if<boost::is_integral<T>, T>::type get()
    {
        return 10;
    }
    template <typename T>
    typename boost::disable_if<boost::is_integral<T>, std::string>::type get()
    {
        return "string";
    }
};

Обновление «Что делать, если я хочу принять более одного диапазона классов на основе некоторых черт?» struct Scanner { template <typename T> typename boost::enable_if<boost::is_integral<T>, T>::type get() { return 10; } template <typename T> typename boost::enable_if<boost::is_floating_point<T>, T>::type get() { return 11.5; } template <typename T> std::string get( typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0, typename boost::disable_if<boost::is_integral<T>, T>::type* = 0) { return std::string("string"); } };

3 голосов
/ 29 марта 2010

Отложите на другой шаблон. Вот общая схема того, что вы хотите:

template <typename T, bool HasTrait = false>
struct scanner_impl;

template <typename T>
struct scanner_impl
{
    // Implement as though the trait is false
};

template <typename T>
struct scanner_impl<true>
{
    // Implement as though the trait is true
};

// This is the one the user uses
template <typename T>
struct scanner : scanner_impl<T, typename has_my_trait<T>::value>
{
};
...