0

我想创建一个具有单个 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 有一个名为“阈值”的变量,算法 B 需要该信息,因此,通常它必须使用 A.getThreshold 之类的东西从 A 询问它,但据我所知,我可以t 在字符串中调用一个对象函数(来自 xml 文件),所以我的解决方案是只有一个 get 函数,我传递我想要的变量名,该函数会将它返回给我。

4

4 回答 4

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");

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

于 2012-06-11T20:04:06.343 回答
1

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

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

如果存储在 中的类型不完全正确,则调用将失败并出现boost::bad_any_cast异常。any T

于 2012-06-11T19:47:17.970 回答
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;
}

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

于 2012-06-11T20:27:15.080 回答
0

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

于 2012-06-11T19:48:36.027 回答