返回不同类型变量的单一get方法

时间:2012-06-11 19:44:14

标签: c++ boost return-type boost-any

我想创建一个具有单个get模板方法的类,该方法将接收std :: string以在std :: map中找到正确的变量并返回它。

std :: map应该存储任何类型的变量,所以我使用了boost :: any,到目前为止std :: map看起来像这样:

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

对于get函数,我尝试过类似的东西:

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

但没有幸运,我的问题是,甚至可以做到吗?如果是这样,怎么样?

基本的想法是我不想为我的类中的每个特定变量创建一个特定的方法,所以其他类不需要知道它的每个get方法。

谢谢!

ps:对于任何问我为什么要这样的人,这里有一个简历,我有很多算法,它们将按照一定的顺序运行,并且它将用于最后一个已经运行的算法。所以,我想要的是制作一个xml文件,它将告诉运行什么算法,以及从其他算法中使用的数据顺序和数据。

因此,例如,算法A有一个名为“threshold”的变量,算法B需要该信息,因此,通常它必须使用像A.getThreshold这样的东西从A中询问它,但据我所知,我不能用字符串(来自xml文件)调用一个带有它名字的对象函数,所以我的解决方案只有一个get函数,我传递了我想要的变量名,该函数将它返回给我。

4 个答案:

答案 0 :(得分:2)

另一种解决方案是将boost::any对象“包装”到另一个对象中,该对象可以自动转换为您想要的任何对象。我不认为这是一个很好的做法,但根据你的问题,这是最合适的。

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

你的吸气器会是这样的:

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

然后你应该能够检索你的元素:

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

但同样,这不是一个干净的解决方案。升级作者选择将any_cast明确表示是有原因的:)

答案 1 :(得分:1)

boost::any值不会隐式转换为T类型,您必须手动请求转换:

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

如果boost::bad_any_cast中存储的类型不是 any,则调用将失败并显示T例外。

答案 2 :(得分:0)

您还可以返回boost::any。您将失去对实现的封装,但取决于您如何使用返回值,这可能是更好的方法。

答案 3 :(得分:0)

当您尝试混合编译时(模板)和运行时(地图查找)代码时,您无法实现所需。

您必须使其完全运行:

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]; }

或完全编译时间(boost.fusion示例):

#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;
}

考虑到您在问题中提供的信息,我会选择具有动态多态性的运行时变体。