6

Interface:

template <class T>
class Interface{
    public:
    typedef T Units;
    virtual T get() = 0;
};

Implementation1:

class Implementation1: public Interface<float> {
    public:

    float get() {
       return 0.0f;
    }

};

Implementation2:

class Implementation2: public Interface<int> {
    public:

    int get() {
       return 0;
    }

};

Container (with errors):

class Container{
    private:
    Interface* floatGetter;
    int n;
    Timer::Units* array;

    public:
    Container(Interface* floatGetter, int n) {
        this->floatGetter= floatGetter;
        this->n = n;
        array = new Timer::Units[n];
    }

    ~Container() {

    }

};

For more details, I have a template interface and a derived class from this interface without template. Some other class take an object of the derived class but it takes the object as an interface (in other words, dependency injection). But the type of the interface in this class is defined by the interface implementation. How to implement this idea in C++?

Edit1:

Example:

Interface<float> myInterface1 = new Implementation1();
Interface<int> myInterface2 = new Implementation2();
Container container1 = new Container(myInterface1, 10);
Container container2 = new Container(myInterface2, 10);

I need that container understands interface template argument from its implementation.

itun
  • 3,439
  • 12
  • 51
  • 75

2 Answers2

6

OK, first, an explanation of the problem here. What's required is an interface, that defines a virtual method, used to get a value with a templated type. Since what we want is an interface, the get method has to be virtual. On the other hand, we would like to be able to return different types, so we want to templetize it. However, a virtual method can not be templetized, because the compiler wouldn't know which instantions of that method to include in the vtable.

One solution is to do what's done in the question, i.e. templetize the interface class. An important property of template types is that different instantiations of the same class are completely different types. They don't share a common base, and they're not convertible to each other. We simply can not have an Interface<Generic> pointer going around in regular functions, with their get() methods being called. Consider this: Every instantion of the Interface template type has a different signature for the get() method. This means that while that method is being called, different things have to happen on the stack. How could the compiler know which version of the get() method to call (how to prepare the stack for the function call) if all it has is a Interface<Generic> pointer.

I can think of two general solutions to that problem.

  1. Remove all template mumbo-jumbo and make the get() method return a type-erased object, such as boost::variant or boost::any. Correct me if I'm wrong here(*), but boost::variant is like a union that remembers which type of the union is assigned, while boost::any is like a void *, but it remembers what type it's pointing to. This solution path implies two things: a) The types of the returned objects will be resolved at runtime, and there will be some overhead while manipulating these types. b) The child classes of Interface will have to manage one of these type-erased objects, making them more complicated.

  2. Take the template mumbo-jumbo to the extreme and refer to Interface objects always in a templetized context, so that the compiler generates the right function calls during the instantiations of those contexts. I gave an example below which follows this path. The example creates a container for holding together different types of Interface<> objects, while enabling the application of templetized functionals (is it correct to call this generally "visitors"?) to them. Note that in that example, the Interface objects with different type parameters are actually kept in different std::lists in that container class, so in the runtime, there's no need to resolve their types.

Disclaimer: What follows is an overkill...

Here's how you can have a container of the "interface" template class with different template arguments. I've used an std::list to keep the instances, but you can change it.

#include<boost/fusion/container/vector.hpp>
#include<boost/fusion/algorithm.hpp>
#include<boost/mpl/transform.hpp>
#include<boost/mpl/contains.hpp>
#include<boost/utility/enable_if.hpp>
#include<boost/type_traits/add_reference.hpp>
#include<list>
#include<algorithm>
#include <iostream>

using namespace boost;

template <class T>
class Interface{
    public:
    typedef T Units;
    virtual T get() = 0;
};

class Implementation1: public Interface<float> {
    public:

    float get() {
       return 0.0f;
    }

};

class Implementation2: public Interface<int> {
    public:

    int get() {
       return 5;
    }

};

template<class element>
struct to_list {
    typedef std::list<Interface<element> *> type;
};

template<class elementVector>
struct to_containers {
    typedef typename mpl::transform<elementVector,to_list<mpl::_1> >::type type;
};

class Container{
    typedef fusion::vector<int,float> AllowedTypes;
    typename to_containers<AllowedTypes>::type containers;

public:
    template<class type> typename enable_if<mpl::contains<AllowedTypes,type>,void>::type 
    /*void*/ add(Interface< type/*included in AllowedTypes*/ > & floatGetter) {
        fusion::deref(fusion::find<typename to_list<type>::type >(containers))
            /*<type> container*/.push_back(&floatGetter);
    }

    template<class functional>
    void apply(functional f) {
        fusion::for_each(containers,applyFunctional<functional>(f));
    }

private:
    template<class functional>
    struct applyFunctional {
        functional f;
        applyFunctional(functional f): f(f){}
        template<class T> void operator()(T & in) const {
            std::for_each(in.begin(), in.end(),f);
        }
    };

};

struct printValueFunctional {
    template<class element>
    void operator()(Interface<element> * in) const {
        std::cout<<"Hi, my value is:"<<in->get()<<"\n";
    }
};

int main() {

    Implementation1 impl1;
    Implementation2 impl2;
    Interface<float> &myInterface1 = impl1;
    Interface<int> &myInterface2 = impl2;
    Container container;
    container.add(myInterface1);
    container.add(myInterface2);
    container.apply(printValueFunctional());
    return 0;
}

And the output is:

Hi, my value is:5
Hi, my value is:0

Well, this really is a huge overkill for most applications, but you asked for it :)

If you just want an interface, that can return different things, you could also consider boost.variant. The example above is truly valuable for all the static polymorphism it uses.

EDIT: David has pointed something important, it might be a pitfall, if you, for some reason, assume otherwise. This container doesn't really stay true to the order of the item insertions. The order of your functional calls might not happen in the order of the insertions of the items, i.e., assume that the iteration will be in a "random" order.

(*) boost::variant and boost::any are discussed here

Community
  • 1
  • 1
enobayram
  • 4,650
  • 23
  • 36
  • 1
    +1 for a fine piece of metaprogramming. I don't think it is a good solution to the problem, but it deserves the rep :) – David Rodríguez - dribeas Feb 01 '12 at 20:37
  • Thanks :) I don't think it is a good solution to the problem in general either, but it just shows that template metaprogramming allows this without type erasure. You also get a mixed container with very fast iteration. – enobayram Feb 01 '12 at 21:23
  • It is not really a mixed container (or is it?)... but a type that holds multiple containers internally. To me the difference is in the fact that the different types are still separated internally, even if you have the impression that they are not, and that means that while with type erasure you can maintain the container invariants (for example, the order of insertion in sequence containers), you cannot do the same with this approach (to be honest this is just a hunch, I have read over the code, but have not compiled/tried it) – David Rodríguez - dribeas Feb 01 '12 at 21:30
  • Well, it looks like a mixed container, it acts like a mixed container and it smells like one too. But I still get your point, If you expanded all the template instantiations, everything that results from the metafunctions, it is no different than writing the real container classes one after each other and handling the types separately by hand. That's also where the magic is, it's equivalent to doing that, yet there is no code duplication... (and no maintenance headache) – enobayram Feb 01 '12 at 21:42
4

Interface is a template, not a type. The variables in your class should be the instantiation of the template with a particular type, as:

class Container {
    Interface<float> *floatGetter;

And similarly for the argument to the constructor.

Side note: your destructor should free the resources that your class handles.

Side note 2: it is quite hard to write a type that directly manages more than one resource, consider using smart pointers to hold your data.

Side note 3: learn and use initialization lists.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Your *constructor* should free the resources? – Jesse Good Feb 01 '12 at 01:20
  • @jesse thanks for catching the typo... Of course the destructor should free the resources, rather than the constructor. – David Rodríguez - dribeas Feb 01 '12 at 01:22
  • @itun what you are now asking for is not doable in simple C++, I think you misunderstood what templates are. A template does to define a type, but a family of them. `interface` is completely unrelated to `interface`. Now, there are some things that can be done, but you will need to explain your requirements before the problem can be tackled (if it can at all). The options range in complexity from making `container` a template (simple, but might just push the problem yif you intended to use different `container`s polymorphically) to implementing some short of type erasure... – David Rodríguez - dribeas Feb 01 '12 at 04:10
  • With template metaprogramming, you can actually avoid type erasure, and still have different interface objects in the same container. It's a bit complicated, so I'll give a full example in a separate answer if anybody actually cares about it. – enobayram Feb 01 '12 at 15:23
  • @enobayram "I'll give a full example in a separate answer if anybody actually cares about it." - I care, it will be very helpful. – itun Feb 01 '12 at 16:05
  • I've given the full example in my answer. – enobayram Feb 01 '12 at 19:19
  • @enobayram: That is actually stretching a bit the common understanding of what a container is... your `Container` type actually comprises a set of *real* containers, and each element is pushed onto the container of it's own type. Without digging into the gory details, I have the feeling that the order of insertions (a common property of sequence containers) will not be maintained on `Container`, for example... A nice exercise anyway, and I will surely look at the details and how it is implemented under the hood. I still find type erasure (`boost::any`/`boost::variant`) a simpler choice. – David Rodríguez - dribeas Feb 01 '12 at 20:19
  • @DavidRodríguez-dribeas: You're definitely right, you would need some run-time type inference mechanisms to enable maintaining the order of insertions. I don't really know what the fundamental property of a container is, but this approach enables very fast iteration through the items, if you don't care about the order. For 99% of the cases (where that final little bit of performance doesn't matter) type erasure would also be my choice. – enobayram Feb 01 '12 at 21:20