Reputation: 1569
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
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
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
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