txtechhelp
txtechhelp

Reputation: 6777

C++ store template parameter as variable

I'm writing a generic wrapper class for a bunch of classes we have defined in other code. I'm trying to figure out if there is a way in C++ to write a templated class that can store a template parameter as a variable. Here is an example of what I would like to see work:

template < class C > class generic {
    public:
        C obj; // used for custom type processing

        template < class T > T other; // <- changeable variable (or something)

        template < class T > setOther() { // Function to change variable
            // code to change variable type, or set type
        }

        void doSomethingWithOther() {
            // do some processing for other, like call
            // specific member function or something
            (((other*)obj)->*SomeGenericMethod)()
        }
}

int main(int argc, char **argv) {
    Bar bObj;
    generic<Foo> fObj;
    fObj.setOther<Bar>();
    fObj.doSomethingWithOther();
    return 0;
}

I know the above code won't compile for many reasons, but my question is more in regards to functionality. Is there some way that I could store a template parameter as a variable (or use a function or something) that could then be used later as a type specifier? If there is not a standard way, any ideas from the SO community that might lead to my desired results?

Please no Boost or other 3rd party libraries, I'm trying to keep it as "STL" (C99) as possible.

Another idea I had was to use default specializations:

template < class C, class T = void* > class generic {
    public:
        C obj;
        T other;
        // ... more code
}

but in that instance, assuming we had the following:

class Test1 {
    public:
        generic<Foo> *G1;
        generic<Foo, Bar> *G2;
};

If I wanted to change the type of G1 later to do some other processing, I could say something like the following:

G1 = new generic<Foo, Bar>(); // compile error, different types

However, this would result in a compile error since the two types pointed to are of different types (G1 is of type generic< C > the other is of type generic< C, T > even though template class T is defaulted to void*.

Sorry for the long post, I am trying to be as clear as possible in my intentions with this code. As well, please feel free to correct me in any of my statements above (long days=less brain activity for me)

Thanks in advance for any help in this matter.

Edit 1:

To clarify, the other data member is merely there to show that I would like that member to hold a class type. This is because our code has members of other classes calling instanced member functions. And if I were to make a call to a member function of a different class I will get a compile error.

And unfortunately I cannot use any C++0x features as our embedded compilers are older and do not support the 0x feature set. Otherwise that would be the obvious solution.

I am essentially having to build in a delegate type of system so that instanced classes can call members of other instanced classes from within themselves and that called member function will have the memory space and access to the this pointer

Example:

class Foo {
    public:
        Delegate other;
}

class Bar {
    public:
        void SomeFunction() {
            std::cout << "hello from Bar::SomeFunction, data = " << data << std::endl;
        }

        int data;
}

int main() {
     Foo F;
     Bar B;
     B.data = 10;
     F.other = Delegate::attach<Bar>(&Bar::SomeFunction, &B);
     // Delegate::attach is defined as 
     // template < class T > Delegate attach(void (T::*fnPtr)(void*), T *obj)
     F.other();
}

In the above example void operator()() of the Delegate class then calls the other members function, via (*fnPtr)(). If called this way, the function has no access to it's member data (no knowledge of the this pointer). If called passing the referenced object (i.e. (*fnPtr)(obj)), the function now has access to the member data.

I'm trying to solve this via specifying a generic class type object that could then be casted back and forth as the Delegate other may attach to any member.

Upvotes: 4

Views: 8981

Answers (3)

Mooing Duck
Mooing Duck

Reputation: 66952

It's not clear what the problem is that you are trying to solve. In your code, what is the purpose of class C? Anyway, here's a guess at what you want. Use an underlying template class implementation that derives from a common base class with a virtual interface, and have the generic class hold a pointer to that interface.

class generic {
    class interface {
    public:
        virtual ~interface(){}
        virtual void SomeGenericMethod()=0;
    };
    template <class T>
    class implementation: public interface {
        T data;
    public:
        implementation(const T& d) :data(d) {}
        virtual void SomeGenericMethod() 
        {return data.SomeGenericMethod();}
    };
    public:
        std::unique_ptr<interface> data;

        template < class T > void setOther(const T& other) {
            data.reset(new implementation<T>(other));
        }

        void doSomethingWithOther() {
            data->SomeGenericMethod();
        }
};

int main(int argc, char **argv) {
    generic fObj;
    Bar bObj;
    fObj.setOther(bObj);
    fObj.doSomethingWithOther();
    return 0;
}

http://ideone.com/A1Aqu

Upvotes: 3

Georg Fritzsche
Georg Fritzsche

Reputation: 99044

It sounds like your main goal is to call some member function of other.

If that is the case, you don't even need other, but just a functor that encapsulates the call. E.g. with C++11 or TR1:

template <class C> struct A {
    C obj;
    std::function<void ()> op;
    void f() {
        // ...
        op();
    }
};

struct B {
    void g() { std::cout << "moo" << std::endl; }
};

int main() {
    A<int> a;
    B b;
    a.op = std::bind(&B::g, &b);
    a.f();
}

Upvotes: 0

pmr
pmr

Reputation: 59831

If you don't know the exact type at compile time, you cannot encode it as template parameter. Those must be known at compile-time and cannot be changed after that. Check out Boost.Any (any possible type) or Boost.Variant (multiple known types) for examples that can help you. any is implementable with reasonable effort, variant not so much. Given your knowledge about C++ templates you might should not attempt to implement either without really understanding the code in boost, no offense intended.

Upvotes: 0

Related Questions