0

Suppose I have a class called generic_pair of the form:

template < typename K, typename V >
struct generic_pair{
  K key;
  V value;
};

Now, the problem is I would like to be able to store a bunch of these generic_pairs in an STL container BUT not all < K, V > in the container will be of the same type. For example, some elements may be < int, int > whereas others may be < int , string > and so on. Question is how can we do this?

My first thought is to use "tags" to create a hierarchy of encapsulated types and declare the container with the generic type but actual elements with inherited types. For example,

struct base_type{
  typedef void type;
};

struct int_type: base_type{
  typedef int type;
}

struct string_type: base_type{
  typedef std::string type;
}

/// and so on establish a type hierarchy as necessary and then...

std::vector < generic_pair < base_type, base_type > > vec;

I bet there is a better, more correct way to do this? Any ideas, directions appreciated. If you have seen similar implementations or relevant tools/techniques in MPL or elsewhere that's helpful too. (I am trying to avoid macros)

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
kvs
  • 95
  • 1
  • 7
  • As always with a "how can I shoehorn non-polymorphic things into a container" question, you need to work out how you would actually use the container if such a thing were possible. If you iterated through the items, what would you want to be able to do with them? – Oliver Charlesworth Nov 02 '10 at 23:36
  • @Oli: Let's say based on the type of key and/or value I would like to print them out or serialize to disk. Now, how would you "shoehorn" it? – kvs Nov 02 '10 at 23:41

2 Answers2

3

You can use Boost.Variant if the set of types is determined in advance. If not, then Boost.Any might do the trick.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
3

From your question and subsequent comments that clarify matters, the following would do what you're asking for:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

// All class-template instantiations derive from this
struct AbstractPair
{
    virtual std::string serialize() const = 0;
};

template<typename K, typename V>
struct Pair : public AbstractPair
{
public:
    Pair(K key, V value) : key(key), value(value) {}

    std::string serialize() const
    {
        std::stringstream ss;
        ss << "Key: " << key << ", Value: " << value;
        return ss.str();
    }
    K key;
    V value;
};


int main()
{
    // Vector of pointers-to-abstract-base
    std::vector<AbstractPair *> v;

    // Create derived objects (instantiate class template)
    AbstractPair *p1 = new Pair<int,int>(5,10);
    AbstractPair *p2 = new Pair<float,std::string>(3.2f, "Hello");

    // Valid, and type-safe
    v.push_back(p1);
    v.push_back(p2);

    // Demonstrate polymorphism
    for(std::vector<AbstractPair *>::iterator it = v.begin(); it != v.end(); ++it)
    {
        std::cout << (*it)->serialize() << std::endl;
    }

    // Boilerplate cleanup
    delete p1;
    delete p2;
    return 0;
}

}

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • beat me to it... ach well.. :) – Nim Nov 02 '10 at 23:55
  • @kvs: Well, you should mention that kind of restriction in your question! Also: why not? (proof-of-concept code above could be done even more cleanly with smart pointers) – Oliver Charlesworth Nov 03 '10 at 00:11
  • I thought the example and the question implied containers with value semantics. It's easy to shoehorn any type into an STL container with pointers and polymorphism. I am looking for proper value semantics and compile time type-checking etc. (See boost::variant documentation, for example, for list of reasons why pointer & polymorphism may not be suitable). I am writing a library not a program. – kvs Nov 03 '10 at 00:36
  • @kvs: Your question doesn't really imply this at all, but fair enough. My "solution" above doesn't suffer from the problems described in the boost variant docs; it is type-safe, and involves no down-casts (at least, not to solve the problem as you've stated it!). If you can edit your question so as to describe why there could be a problem, then I can respond further... – Oliver Charlesworth Nov 03 '10 at 09:20