Question

I want to make a class that will have a single get template method which will receive an std::string to find in a std::map the right variable and return it.

The std::map should store any type of variable, so I used boost::any, so far the std::map looks like that:

std::map<std::string, boost::any> variables_;

for the get function, I tried something like that:

template <typename T>
T get(std::string& parameter)
{
    return variables_[parameter];
}

But no lucky, my question is, is that even possible to do? If so, how?

The basic idea is that I dont want to make an specific method to every specific variable in my class, so other classes dont need to know about every get method of it.

Thanks!

ps: For anyone asking why I want this, here is a resume of it, I have a lot of algorithms, that will run in a certain order, and it will use that for the last one already runned algorithm. So, what I want is to make an xml file, that will tell what algorithms will run, in which order and what data it will use from another algorithm.

So, for example, algorithm A have an variable named "threshold", algorithm B need that information, so, normally it will have to ask it from the A using something like A.getThreshold, but as far as I know, I can't call a object function with it name in an string (from the xml file), so my solution would be have only an get function which i pass the variable name I want and that function will return it to me.

Was it helpful?

Solution

An alternative solution would be to "wrap" the boost::any object into another object which can be automatically converted to anything you want. I don't think it's a good practice but it's the best fit according to your question.

class AnyWrapper {
    boost::any value;
public:
    AnyWrapper(const boost::any& val) : value(val) {}
    template<typename T> operator T() {
        return boost::any_cast<T>(value);
    }
}

And your getter would be something like :

AnyWrapper get(std::string& parameter)
{
    return variables_[parameter];   // variables is a std::map<std::string, boost::any> 
}

And then you should be able to retrieve your elements like that :

int integerValue = myContainer.get("age");
std::string stringValue = myContainer.get("name");

But again, this is not a clean solution. There is a reason why the boost authors chose to make the any_cast explicit :)

OTHER TIPS

An boost::any value won't implicitly convert to a type T, you have to request that cast manually:

template <typename T>
T get(std::string& parameter)
{
    return boost::any_cast<T>(variables_[parameter]);
}

The call will fail with a boost::bad_any_cast exception if the type stored in the any is not exactly T.

You can also return an boost::any. You lose encapsulation of your implementation, but depending on how you use the return value, it may be the better way.

What you want is not possible as you are trying to mix compile time (template) and runtime (map lookup) code.

You either have to make it fully runtime:

struct base_type { virtual ~base_type{} };
struct derived_type: base_type { ... };
std::map<std::string, base_type*> lookup_map;
base_type* get(std::string const& key) { return lookup_map[key]; }

Or fully compile time (boost.fusion example):

#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>

namespace bf=boost::fusion;

struct key_a; // analogues of string keys in compile time world
struct key_b;
struct key_c;

typedef bf::map<
  bf::pair<key_a, long>,
  bf::pair<key_b, double>,
  bf::pair<key_c, char const*>
> rtmap_t;
rtmap_t rtmap;

template <class Key>
void set_value(typename bf::result_of::value_at_key<rtmap_t, Key>::type const& val)
{
  bf::at_key<Key>(rtmap) = val;
}

template <class Key>
typename bf::result_of::at_key<rtmap_t, Key>::type get_value()
{
  return bf::at_key<Key>(rtmap);
}

#include <iostream>
int main()
{
  char const* cval = "hello metaprogramming";
  set_value<key_a>(123l);
  set_value<key_b>(456.789);
  set_value<key_c>(cval);
  std::cout << get_value<key_a>() << std::endl;
  std::cout << get_value<key_b>() << std::endl;
  std::cout << get_value<key_c>() << std::endl;

  return 0;
}

Considering the information you provided in your question I would choose runtime variant with dynamic polymorphism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top