2014-07-08 14 views
11

Esiste una tecnica/lo stile migliore per raggruppare le specializzazioni di modelli di classe per determinati tipi?Specializzazioni modello di classe di gruppo

Un esempio: Diciamo che ho un modello di classe Foo e ho bisogno di avere si è specializzata la stessa cosa per la tipografia

A = { Line, Ray } 

e in un altro modo per la tipografia B

B = { Linestring, Curve } 

Quello che sto facendo finora: (la tecnica viene anche presentata here per le funzioni)

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

Una struttura di supporto aggiuntiva enable_for accorcia il codice (e consente di scrivere direttamente i tipi accettati). Qualche altro suggerimento, correzioni? Non dovrebbe questo comportare meno sforzo?

+3

È inoltre possibile creare un * tipo_trazioni * per gruppo. – Jarod42

+0

@Angew: ahi, ho perso il modello base. Hai ragione, quelle sono due specializzazioni. –

risposta

13

È anche possibile fare questo con le proprie caratteristiche e senza 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 
}; 

Questo ha il vantaggio di garantire automaticamente che ogni tipo è al massimo in un gruppo.

11

ulteriore livello di indirezione utilizzando due nuovi caratteri morfologici:

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

e poi fare il enable_if su questo tipo tratti

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

Si noti che è comunque necessario assicurarsi che nessun dall'utente la classe definita viene aggiunta a entrambi i gruppi o si otterrà un'ambiguità. È possibile utilizzare la soluzione di @ Angew per derivare da un gruppo numerato utilizzando std::integral_constant<int, N> per il numero di gruppo N. Oppure, se questi gruppi non sono logicamente esclusivi, è possibile aggiungere una condizione aggiuntiva all'interno dello enable_if che protegge da questo.

Problemi correlati