views:

317

answers:

4

Hi everyone, I've been learning C++, coming from C#, where I've gotten used to using service providers: basically a Dictionary<Type, object>. Unfortunately, I can't figure out how to do this in C++. So the questions are basically:

  1. How would I make a dictionary in C++.

  2. How would I use 'Type' with it, as far as I know there is no 'Type' in C++.

  3. Same as above, but with 'object'.

Thanks!

A: 

A dictionary sounds like an STL map to me: std::map<K, T>. Have a look at the Standard Template Library - it's brilliant. It's been part of ANSI C++ for a while. Microsoft has a nice implementation from PJ Plauger, if I recall correctly.

duffymo
The template annotations didn't come through; should read std:map<K, T>
duffymo
use `std::map<K, T>` instead
Johannes Schaub - litb
Thank you, I didn't know.
duffymo
+3  A: 

You probably want to look at the STL map template. C++ certainly does have types (hard to have inheritance without it), just no specific defined "Type" class.

ctacke
+2  A: 

The STL has two associative containers: std::map<K,V> and std::multimap. There is also std::set<V> which should be an adaptor of std::map<V,void>, but as such it isn't an associative container. The multimap is similar to the map, only it allows multiple identical keys within the same container. Both map and multimap hold elements of type std::pair<K,V>. In other words, std::map<K,V>::value_type == std::pair<K,V>, but std::map<K,V>::key_type == K and std::map<K,V>::mapped_type == V.

As for "Type", I am not entirely sure what you mean. If you mean parameterized classes then C++ calls this "Template Programming", or "Generic Programming". In the above, std::map<K,V> is parameterized over K and V for the keys' type and the values' type. C++ also supports template functions:

template<typename T>
void f(T o);

will declare a function that takes as a parameter any type at all, including primitive types. C++ doesn't support generic type resolution, such that the type T must of certain hierarchy. For now, all you can do is just assume the passed type is indeed of the correct hierarchy, and the compiler will complain if you try to call a non-declared function over an object of that type.

template<typename T>
void f(T o) {
    o.do_it();
}

The above will work as long as T defines the method do_it().

wilhelmtell
+5  A: 

I'm assuming that you're trying to map a type to a single object instance. You could try something along these lines:

#include <typeinfo>
#include <map>
#include <string>
using namespace std;

class SomeClass
{
public:
    virtual ~SomeClass() {} // virtual function to get a v-table
};

struct type_info_less
{
    bool operator() (const std::type_info* lhs, const std::type_info* rhs) const
    {
        return lhs->before(*rhs) != 0;
    }
};

class TypeMap
{
    typedef map <type_info *, void *, type_info_less> TypenameToObject;
    TypenameToObject ObjectMap;

public:
    template <typename T> 
    T *Get () const
    {
     TypenameToObject::const_iterator iType = ObjectMap.find(&typeid(T));
     if (iType == ObjectMap.end())
      return NULL;
     return reinterpret_cast<T *>(iType->second);
    }
    template <typename T> 
    void Set(T *value) 
    {
     ObjectMap[&typeid(T)] = reinterpret_cast<void *>(value);
    }
};

int main()
{
    TypeMap Services;
    Services.Set<SomeClass>(new SomeClass());
    SomeClass *x = Services.Get<SomeClass>();
}

In C++ types are not first-class objects in their own right, but at least the type-name is going to be unique, so you can key by that.

Edit: The names aren't actually guaranteed to be unique, so hold on to the type_info pointers and use the before method to compare them.

Eclipse
Thanks, this is great.
Sean James
Rather than use a string, you could use the address of a static property of each ServiceProvider class
Frank Schwieterman
Wrong: typeid(T).name is NOT unique. typeid(T) does have an operator== to compare typeinfo objects. See e.g. type_info_cmp on http://tangentsoft.net/mysql++/doc/html/refman/type__info_8h-source.html
MSalters