2009-07-10 9 views
5
template<typename T> 
class vec3 
{ 
public: 
    typename T type_t; 
    T x; 
    T y; 
    T z; 
}; 

template<typename T> 
struct numeric_type_traits_basic_c 
{ 
    typedef T type_t; 
    typedef T scalar_t; 
}; 

template<typename T> 
struct numeric_type_traits_vec3_c 
{ 
    typedef T type_t; 
    typedef typename T::type_t scalar_t; 
}; 

typedef numeric_type_traits_basic_c<int> int_type_traits; 
typedef numeric_type_traits_vec3_c< vec3<int> > vec3_int_type_traits; 

Questo è un tipo di tratto per scalare e vettore, l'unica differenza è che il tipo scalare, per un vettore, è il tipo del suo elemento. Funziona bene.specializzazione caratteri tipo

Ma mi piacerebbe davvero essere in grado di usare lo stesso nome per quelle due classi.

template<typename T> 
struct numeric_type_traits_c 
{ 
    typedef T type_t; 
    typedef ????? scalar_t; 
}; 

So che questo è possibile farlo se la classe è esplicitamente specializzato per ogni tipo ho bisogno: int, float, vec3, vec3 ...

Questo è un sacco di doppioni ... Come posso mantenere la semplicità del primo bit di codice ma avere lo stesso nome di classe allo stesso tempo?

risposta

5

Questa è la sintassi per la parziale modello di classe di specializzazione:

template<typename T> 
struct numeric_type_traits // basic template 
{ 
    typedef T type_t; 
    typedef T scalar_t; 
}; 

template<typename T> 
struct numeric_type_traits< vec3<T> > // partial specialisation for vec3's 
{ 
    typedef vec3<T> type_t; 
    typedef T scalar_t; 
}; 

E così via, per esempio:

template <typename T, typename T_Alloc> 
struct numeric_type_traits< std::vector<T,T_Alloc> > // part. spec. for std::vector 
{ 
    typedef std::vector<T,T_Alloc> type_t; // deal with custom allocators, too 
    typedef T scalar_t; 
}; 
0

Forse dovresti creare un'istanza del tuo modello con due tipi? Vedi:

template<typename TYPE, typename SCALAR> 
struct numeric_type_traits_c 
{ 
    typedef TYPE type_t; 
    typedef SCALAR scalar_t; 
}; 

typedef numeric_type_traits_c<int,int> int_type_traits; 
typedef numeric_type_traits_c<vec3<int>, vec3<int>::type_t> vec3_type_traits; 
+0

L'intenzione alla base del carattere è quella di evitare che il tipo di carattere sia supposto di fornire tali informazioni –

0
template<typename T> 
struct numeric_type_traits_c 
{ 
     typedef T type_t; 
     typedef T scalar_t; 
}; 

template<typename T> 
struct numeric_type_traits_c<vec3<T> > 
{ 
     typedef vec3<T> type_t; 
     typedef typename vec3<T>::type_t scalar_t; 
}; 

Sì, di sicuro ho fatto un errore nel type_t per vec3!

0

Un'osservazione interessante risiede nell'applicare la conoscenza che abbiamo da polimorfismo dinamico alla polimorfismo "funzione tipo".

Se si confronta questa funzione f:

struct I { virtual double f()const = 0; }; // C++ version of 'an interface' 
struct A : public I { virtual double f()const{ return 0; } }; 
struct B : public I { virtual double f()const{ return 1; } }; 
struct C { }; 

void f(const I& i){ return I.f(); } 

f(A()); 
f(C()); // compiler warning: wrong type provided. 

con questa funzione f:

// struct TI { typedef ??? iT; }; // no C++ version of a type-interface 
struct TA { typedef int iT; }; 
struct TB { typedef double iT; }; 
struct TC { }; 

template< typename aTI > struct fT { typedef aTI::iT returnType; }; 

fT<TA>::returnType vA; 
ft<C>::returnType vC; // compiler error: C has no iT member. 

Si vede che l'unica differenza è la notazione dei parametri. La prima funzione è una funzione polimorfa 'regolare'. Il compilatore ci avviserà se l'argomento fornito non è del tipo corretto.

fT è una funzione che può essere utilizzata dal compilatore solo per determinare un determinato tipo. Prende un tipo come argomento. Ma il linguaggio non ha "concetto" di un vincolo di tipo (ancora - vedi Concetti in C++ 0x). Quindi dobbiamo garantire a mano che i tipi che usiamo per una funzione tipo "implementino" l'interfaccia corretta.

In concreto, questo si riduce all'aggiunta del tipo scalar_t a qualsiasi classe che si desidera utilizzare con la funzione di tipo numeric_type_traits_c.