Mark
Mark

Reputation: 1569

C++ template type that can be stored in a std::map and then exposing the map publicly

I have a class myclass that has a private member param_map

class some_class {

 private:
  std::map<std::string,std::shared_ptr<parameter> > param_map;
};

I want to expose this map to allow other classes, I have already created add, delete, get parameter methods, which do, what you think. But I would like to expose this so other classes can traverse the map.

Q1: What would be the safest way to do this.

parameter also has a member value that I want to be either int/float/bool so one option would be to define it using templates

template<class T>
class parameter {
  public:
   T get_value { return value_; }

  private:
   T value_;
}

Q2: But how would I store this type in the map? And how would it change the definition of param_map. Also I would consider non template solutions (But I would prefer just one map)

PS: I would rather avoid using boost, I prefer to use the c++x0 std lib, but if boost is the best option then I will consider that. It would be good if you could post code examples also.

Regards

Mark

Upvotes: 0

Views: 817

Answers (3)

Ferruccio
Ferruccio

Reputation: 100638

Q1: You can provide a foreach() member function which accepts a functor as an argument. The foreach function would traverse the map and call the functor on each item in the map. The caller could then use a C++0x lambda function to create the functor.

#include <string>
#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

class container {
public:
    container() {
        _m["one"] = 1;
        _m["two"] = 2;
        _m["three"] = 3;
    }

    template <class FN>
    void foreach(FN func) {
        std::for_each(_m.begin(), _m.end(), func);
    }

private:
    map<string, int> _m;
};

void main(int, char** a)
{
    container c;
    c.foreach([](pair<string,int> p) -> void {
        cout << p.first << ", " << p.second << endl;
    });
}

I don't have a C++0x compliant compiler handy, so this may need some tweaking to compile.

Q2: I know you don't want to use boost, but I think boost.variant may be your be your best option here. You could use a discriminated union instead but I would be very hesitant to give up the type safety boost.variant gives you.

enum type { int_t, float_t, bool_t };

struct item {
    type t;
    union {
        int i;
        float f;
        bool b;
    };
};

Upvotes: 1

Alexandre C.
Alexandre C.

Reputation: 56956

I'd go with boost::any for the template type. You can reimplement it yourself (as an excellent exercise), but this is wasting your time.

As for Q1, why not simply make the map public? You'll end up providing accession functions for most of the methods in map, like operator[], iterators, etc. So making it public is not a bad idea:

struct MyClass 
{
    map<string, any> parameters;

    // For convenience
    template <typename T>
    T const& getParameter(string const& s) const
    {
        map<string, any>::const_iterator i = parameters.find(s);
        if (i == parameters.end()) throw /* something */;
        return any_cast<T const&>(*i);
    }

    template <typename T>
    T& getParameter(string const& s)
    {
        map<string, any>::iterator i = parameters.find(s);
        if (i == parameters.end()) throw /* something */;
        return any_cast<T&>(*i);
    }
};

MyClass x; 
x.parameters["foo"] = 2.5;
x.parameters["bar"] = string("Hey");
double xfoo = x.getParameter<double>("foo");
string const& xbar = x.getParameter<string>("bar");
for_each(x.parameters.begin(), x.parameters.end(), baz);

Upvotes: 0

amit kumar
amit kumar

Reputation: 21012

Q1: You can expose an iterator that iterates over the map, just like std::map does.

Q2: You can use 3 different maps, or use boost::any to store the value. If you want to avoid boost, you can store void* in place of boost::any (but I would usually not go the void* way -- I would rather use the required parts of boost).

Upvotes: 1

Related Questions