Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ defining type of a member class without template argument

I am trying to set the type of the member of a class, without passing it through template argument.

In details:

// Forward declaration:        
class A;        
class B;

class Base
{
};    

template <class T>    
class Derived : public Base
{    
    private:
        T2 var;    
};

where T could be either class A or class B. What I would like to do is for Derived<A> T2 is int (for instance) and for Derived<B> T2 is double (for instance). I would like to avoid the following solution:

template <class T1, class T2>
class Derived : public Base
{
    private:
        T2 var;
};

I want to avoid this because for Derived<A> there could be various possible combinations for T2: Derived<A,int>, Derived<A,double>, ...

What I want is that the type of T2 is unique for the entire Derived<A>.

Any idea how to solve that ?

like image 862
Christophe J. Ortiz Avatar asked Mar 07 '14 08:03

Christophe J. Ortiz


1 Answers

Update: The comments show that the original problem you are trying to solve is not completely explained in the question. I'll leave the original answer nevertheless at the bottom of this answer.

You cannot have two Derived<A> with different types T2 for the var member. In addition, a variable defined by the User can not influence the type of the member variable. Variable values are set at runtime, types are determined at compiletime.

To store a type somehow defined by the user, you will have either have to restrict the variable to a set of known types or use one type that contains a serialized version of the variable's content. The set of known types is often used in the context of databases, where the fields can have one of several predefined types (e.g. String, Integer, Boolean, Double). The type for the member variable then could be a Boost.Variant, restricted to C++ representations of that type. Another application of "user defined types" are where the user of your program has to somehow define the layout and interpretation of the type and its object, for example if your program is the interpreter of some scripting language. In that case again a Boost.Variant (or something similar) can be of use, or, since the value is probably some user provided input, just store the serialized value in a string and interpret it every time you have to deal with it.

Original answer:

This is usually done via template metaprogramming, in this case a type function (sometimes, depending on the context, part of a traits or policy class):

template <class T>
struct DerivedMemVarType {
  typedef double type; //default
};

template<>
struct DerivedMemVarType<A> {
  typedef int type;
};

And then:

template <class T>    
class Derived : public Base
{  
  typedef typename DerivedMemVarType<T>::type T2;  
private:
  T2 var;    
};

You can also leave out the default, so that any instantiation of Derived for a type that you have not mapped in your function will give a compile error:

template <class T>
struct DerivedMemVarType; //default is not defined

template<>
struct DerivedMemVarType<A> {
  typedef int type;
};

template<>
struct DerivedMemVarType<B> {
  typedef double type;
};

//...

Derived<C> dc; // ...template error mess.... 
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'
like image 181
Arne Mertz Avatar answered Oct 31 '22 20:10

Arne Mertz