Christophe J. Ortiz
Christophe J. Ortiz

Reputation: 319

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 ?

Upvotes: 8

Views: 4374

Answers (3)

Arne Mertz
Arne Mertz

Reputation: 24626

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>'

Upvotes: 7

Coert Metz
Coert Metz

Reputation: 902

I think you can create a separate class that just holds a typedef which you then specialize and use in your Derived class.

template<typename T>
class VarType {
  public:
    typedef int TheType;
}

template <>    
class VarType<B> {    
  public:
    typedef double TheType;
};

template <typename T>    
class Derived : public Base {    
  private:
    typename VarType<T>::TheType var;    
};

Upvotes: 0

Zaiborg
Zaiborg

Reputation: 2522

if you do not have any type specific function call, you can use something like...

class A;        
class B;

class Base
{
};    

template <class T>    
class Derived : public Base
{   
    public:
        Derived(T startVal):var(startVal){}
    private:
        T var;    
};

template <typename T>
Derived<T> MakeDerived(T initValue)
{
    return Derived<T>(initValue);
}

and now you can use it the following and the compiler should know what type you are passing to the function.

int initialValue = 0;
auto derived = MakeDerived(initialValue);

Upvotes: 0

Related Questions