tags:

views:

126

answers:

4

Hi,

I have a problem with template and wondering is there a possible way to achieve what I wanted to do. Here is my question.

template <typename T>
class A
{
public:

    typedef T*              pointer;
    typedef const pointer   const_pointer;

    A()
    {}

    template <typename D>
    A(const D& d)
    {
        // how can I store the D type 
        // so I can refer it later on
        // outside of this function
    }
};

ok here is a more complete code of what I wanted to do (it might not be compilable)

    class C
{
public:
    virtual ~C(){}

    virtual void* get_d() = 0;
private:

};

template <typename T, typename D>
class Cimpl : public C
{
public:
    Cimpl()
    :t()
    ,d()
    {}

    Cimpl(const T& t, const D& d)
    :t(t)
    ,(d)
    {}

    void* get_d()
    {
        return &reinterpret_cast<D&>(d);
    }

private:
    T t;
    D d;
};

class B
{
public:
    B()
    :p(0)
    {}

    template <typename T, typename D>
    B(const T& t, const D& d)
    :p(0)
    {    
        try
        {
            p = new Cimpl<T, D>(t, d);
        }
        catch(...)
        {
            d(p);
        }
    }

    void* get_d()
    {
        return (p != 0) ? p->get_d() : 0;
    }

    ~B()
    {
      delete p;
    }

private:
    C* p;
};

template <typename T>
class A
{
    struct example_d
    {
    };

public:

    typedef T*              pointer;
    typedef const pointer   const_pointer;

    A()
    {}

    template <typename D>
    A(const T& t)
    :b(t, example_d())
    {
    }

    template <typename D>
    A(const T& t, const D& d)
    :b(t, d)
    {
        // how can I store the D type 
        // so I can refer it later on
        // outside of this function
    }

    // not type safe...as user can cast to any type
    // if I can store the type user pass in previous
    // then I can use it back
    template <typename T>
    T* get_d()
    {
        reinterpret_cast<T*>(b.get_d());
    }

private:
    B b;
};

So I can use the class like

1)A<int> a(1);// with example_d as D
2)A<int> b(1, another_d()) // with another_d

I can change the template to take 2 parameters and use default parameter for 2nd type to be example_d. So I can achieve 1) but not 2). As I will have to code this way

A<int, another_d> b(1, another_d()); 

a bit too long to type...

+3  A: 

You cannot store a type, you can only store objects.

(If you want to store the parameter d passed to A's constructor, look at type erasure.)

sbi
That is an excellent link on type erasure.
iain
+2  A: 

You can't "save" a typename like that. What you really want to do is make type D one of the template parameters of the class, e.g.

template <typename T, typename D>
class A
{
public:

    typedef T*              pointer;
    typedef const pointer   const_pointer;

    A()
    {}

    A(const D& d)
    {
    }
};

Now, if your problem is that you want A<T> constructed with type D to be polymorphic with A<T> constructed with type E instead of having A<T,D> and A<T,E> be two different types, then the solution is a base class:

template <typename T>
class ABase
{
public:

    typedef T*              pointer;
    typedef const pointer   const_pointer;

    ABase()
    {}

protected:

    /* You might want to omit this constructor completely, 
     * depending on your use case */

    template<typename D>
    ABase(const D& d)
    {
    }
};

template <typename T, typename D>
class A : public ABase<T>
{
public:

    A()
    {}

    A(const D& d)
      : ABase(d)
    {
    }
};
Tyler McHenry
A: 

If you want to use type D in other member functions of class A, you can make D a second template parameter of class A.

Dima
actually I knew this but I only need one template parameter for the class. So wondering is there a way to do. thanks
stephenteh
Is there any reason why you absolutely can't have two template parameters? If that's the case, you can derive A from another class Abase, which would take D as its template parameter.
Dima
@stephenteh: How about you telling us what you want to store `D` for?
sbi
@Dima: Usually you don't want `D` as a template argument, because you want argument deduction to kick in so you don't have to spell it out.
sbi
+1  A: 

This looks like you are trying to create a template class that has a boost::any member variable. You should look at this a possible way of doing this.

Basically a boost::any can accept any value type. You can then retrieve that type safely if you know the type later. A good example of how you would use this is to store different datatypes in a map, (where you know the type later when you retrieve the the any by its name).

If this is not exactly what you are looking for the internals use a neat trick to implement it, and it will probably help you achieve what you are trying to do.

iain