Reputation:
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;
This is type traits for scalar and vector, the only difference is that the scalar type, for a vector, is the type of its element. Works fine.
But I'd really like to be able to use the same name for those two classes.
template<typename T>
struct numeric_type_traits_c
{
typedef T type_t;
typedef ????? scalar_t;
};
I know this is possible to do so if the class is explicitly specialized for each type I need: int, float, vec3, vec3...
That's a lot of duplication... How can I keep the simplicity of the first bit of code but have the same class name at the same time?
Upvotes: 6
Views: 2914
Reputation: 41519
An interesting remark here lies in applying the knowledge we have from dynamic polymorphism to the 'type function' polymorphism.
If you compare this function 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.
with this function 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.
You see that the only difference is the notation of the parameters. The first function is a 'regular' polymorphous function. The compiler will warn us if the provided argument is not of the proper type.
fT is a function that can only be used by the compiler to determine a certain type. It takes a type as argument. But the language has no "concept" of a type-constraint (yet - see Concepts in C++0x). So we need to hand-guarantee that the types we use for a type-function 'implement' the correct interface.
In concreto, this boils down to adding the scalar_t
type to any class you want to use with the numeric_type_traits_c
type function.
Upvotes: 0
Reputation: 25323
This is the syntax for partial class template specialisation:
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;
};
And so on, e.g.:
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;
};
Upvotes: 5
Reputation: 4659
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;
};
Yes, for sure I've made a mistake in type_t for vec3!
Upvotes: 0
Reputation: 2551
Maybe you should instantiate your template with two types? See:
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;
Upvotes: 0