2014-01-12 3 views
1

Возможно ли сделать компилятор между шаблонами в зависимости от типа? Например, рассмотрим две реализации шаблона функциональности Compare, один для последовательных типов (string s, vector s, list и т. Д.), А другой для целых типов. Можем ли мы иметь только одну специализацию по шаблону для каждого класса типов?Специализация шаблона ограничена условием

template <class SeqT> 
class Compare 
{ 
public: 
    bool operator()(const SeqT& s1, const SeqT& s2) const 
    { 
     typename SeqT::const_iterator it1=s1.begin(); 
     typename SeqT::const_iterator it2=s2.begin(); 
     while(it1!=s1.end() && it2!=s2.end()) 
     { 
     if(*it1<*it2) return true; 
     if(*it2<*it1) return false; 
     ++it1; ++it2; 
     } 
     return it2!=s2.end(); 
    } 
}; 

template <class IntegerT> 
class Compare 
{ 
public: 
    bool operator()(IntegerT i1, IntegerT i2) const 
    { 
     return i1<i2; 
    } 
}; 

template <class T, class Cmp = Compare<T> > 
class SomeContainer 
{ 
    ... 
}; 

В принципе, то, что я ищу способ частично специализировать шаблон путем наложения условия на аргумент шаблона. Подобно первая Compare<> специализация должна быть применена к следующим типам: std::basic_string<>, std::vector<>, std::list<>, и второй для следующих типов: int, unsigned, short, char. Это возможно?

+0

Да. Посмотрите на std :: enable_if – bolov

+0

Сначала я думал о 'std :: enable_if', но я думаю, что лучше добавить параметр шаблона, который указывает тип типа, и который может быть« вычислен »TMP из базового типа. Затем просто укажите специализации. –

+0

Что вы подразумеваете под последовательностью - вы имеете в виду любой объект, который можно повторить с помощью синтаксиса 'for (auto x: y)'? – Yakk

ответ

2

Это мой ответ на другой вопрос, но это то, что вам нужно. Он использует SFINAE для создания специализированного шаблона только для аргументов шаблона, которые проверяют true для условия (например, для определенного типа).

https://stackoverflow.com/a/20898554/2805305

Редактировать

Но как я могу точно указать, что первое сравнение специализации может быть применен к, например, std :: basic_string и std :: vector?

Вы создаете признак, который говорит вам, если T является вектором или basic_string или список:

#include <iostream> 
#include <vector> 
#include <string> 
#include <list> 
#include <complex> 
#include <type_traits> 
using namespace std; 

template <class T> 
struct is_seq : std::false_type { 
}; 

template <class T> 
struct is_seq<std::vector<T>> : std::true_type { 
}; 

template <class T> 
struct is_seq<std::basic_string<T>> : std::true_type { 
}; 

template <class T> 
struct is_seq<std::list<T>> : std::true_type { 
}; 

template <class T> 
using enable_if_seq_type = typename std::enable_if<is_seq<T>::value>::type; 

template <class T> 
using enable_if_integral_type = typename std::enable_if<std::is_integral<T>::value>::type; 


template <class T, class Enable = void> 
class Compare; // <-------- define if you want a Compare for any type that doesn't match any specialization 

template <class T> 
class Compare<T, enable_if_seq_type<T>> { // specialization for T a vector, string or list 
    public: 
     void foo() { 
      cout << "vector, string and list specialization" << endl; 
     } 
}; 

template <class T> 
class Compare<T, enable_if_integral_type<T>> { // specialization for T an integral type 
    public: 
     void foo() { 
      cout << "integral specialization" << endl; 
     } 
}; 


int main() { 
    cout << std::boolalpha; 

    cout << is_seq<int>::value << endl; // false 
    cout << is_seq<std::vector<int>>::value << endl; // true 

    Compare<int> c1; // uses second specialization 
    c1.foo(); // output "integral specialization" 

    Compare<std::vector<int>> c2; // uses first specialization 
    c2.foo(); // output "vector, string and list specialization" 

    //Compare<std::complex<int>> c3; 
    // compile error if you just declare and not define the generic Compare. 
    // If you define the generic Compare, this will compile and it will use 
    // that definition 

    return 0; 
} 

http://ideone.com/JUbwla

Если вы хотите, чтобы иметь возможность создать экземпляр класса Compare для любого другого типа , то вы определяете первое (общее) объявление Compare.

+0

Спасибо. Но как я могу точно указать, что первая сравнительная специализация может быть применена к, например, std :: basic_string и std :: vector ? Кроме того, мне не нужно компилировать _fail_, но компилятор для _choose_ соответствующего шаблона, когда аргумент типа соответствует некоторому условию. Таким образом, как в приведенном выше примере, если экземпляр SomeContainer создан, тогда используется Compare , и если экземпляр SomeContainer используется, тогда используется Compare . – bkxp

+1

@bkxp Я отредактировал свой ответ. – bolov

+1

@bolov Приведенный выше подход имеет проблему. Простая проблема заключается в том, что 'std :: vector' с необычным распределителем,' std :: string' с чертами char не по умолчанию и т. Д. Все не работают. Основная проблема заключается в том, что сохранение списка «шаблонов» или типов, которые соответствуют условию, часто является плохой идеей, по сравнению с выполнением какого-либо типа тестирования утиного типа. – Yakk