2014-07-08 13 views
11

Czy istnieje technika/najlepszy styl do grupowania specjalizacji szablonów klas dla określonych typów?Specjalizacje w szablonach klas grupowych

Przykład: Powiedzmy, że mam klasy szablonu Foo i muszę mieć to wyspecjalizowane takie same dla składania tekstu

A = { Line, Ray } 

oraz w inny sposób dla typeset B

B = { Linestring, Curve } 

Co robię do tej pory: (technika jest również przedstawiona jako here dla funkcji)

#include <iostream> 
#include <type_traits> 
using namespace std; 

// 1st group 
struct Line {}; 
struct Ray  {}; 
// 2nd group 
struct Curve  {}; 
struct Linestring {}; 

template<typename T, typename Groupper=void> 
struct Foo 
{ enum { val = 0 }; }; 

// specialization for the 1st group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_same<T, Line>::value || 
    is_same<T, Ray>::value 
>::type> 
{ 
    enum { val = 1 }; 
}; 

// specialization for the 2nd group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_same<T, Curve>::value || 
    is_same<T, Linestring>::value 
>::type> 
{ 
    enum { val = 2 }; 
}; 

int main() 
{ 
    cout << Foo<Line>::val << endl; 
    cout << Foo<Curve>::val << endl; 
    return 0; 
} 

Dodatkowa struktura pomocnicza enable_for skróciłaby kod (umożliwiając bezpośrednie zapisanie akceptowanych typów). Jakieś inne sugestie, poprawki? Czy nie powinno to wiązać się z mniejszym wysiłkiem?

+3

Możesz także utworzyć * type_traits * według grupy. – Jarod42

+0

@Angew: ouch, przegapiłem szablon podstawowy. Masz rację, to są dwie specjalizacje. –

Odpowiedz

13

Można również zrobić to z własnych cech i bez enable_if:

// Traits 

template <class T> 
struct group_number : std::integral_constant<int, 0> {}; 

template <> 
struct group_number<Line> : std::integral_constant<int, 1> {}; 

template <> 
struct group_number<Ray> : std::integral_constant<int, 1> {}; 

template <> 
struct group_number<Linestring> : std::integral_constant<int, 2> {}; 

template <> 
struct group_number<Curve> : std::integral_constant<int, 2> {}; 


// Foo 

template <class T, int Group = group_number<T>::value> 
class Foo 
{ 
    //::: whatever 
}; 

template <class T> 
class Foo<T, 1> 
{ 
    //::: whatever for group 1 
}; 

template <class T> 
class Foo<T, 2> 
{ 
    //::: whatever for group 2 
}; 

Ma to tę zaletę, automatycznie zapewniając, że każdy typ jest w co najwyżej jednej grupy.

11

dodatkowy poziom pośredni przy użyciu dwóch nowych cech Typ:

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

template<> 
struct is_from_group1<Line>: std::true_type {}; 

template<> 
struct is_from_group1<Ray>: std::true_type {}; 

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

template<> 
struct is_from_group2<Curve>: std::true_type {}; 

template<> 
struct is_from_group2<Linestring>: std::true_type {}; 

a następnie wykonaj enable_if na tego typu cech

// specialization for the 1st group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_from_group1<T>::value 
>::type> 
{ 
    enum { val = 1 }; 
}; 

// specialization for the 2nd group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_from_group2<T>::value 
>::type> 
{ 
    enum { val = 2 }; 
}; 

Należy pamiętać, że trzeba jeszcze upewnić się, że nie ma dla użytkownika zdefiniowana klasa zostanie dodana do obu grup lub uzyskasz niejasność. Możesz użyć rozwiązania @ Angew do wyprowadzenia z numerowanej grupy przy użyciu std::integral_constant<int, N> dla grupy o numerze N. Lub, jeśli te grupy nie są logicznie wyłączne, możesz dodać dodatkowy warunek wewnątrz enable_if, który chroni przed tym.

Powiązane problemy