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

single get method which return different type variables

本文关键字:单个 get 方法 类型变量 返回      更新时间:2023-10-16

我想创建一个具有单个获取模板方法的类,该方法将接收一个 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 函数,我传递我想要的变量名称,该函数将返回它给我。

另一种

解决方案是将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);
    }
}

你的getter将是这样的:

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是有原因的:)

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

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

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

您也可以返回boost::any 。您将失去实现的封装,但根据您使用返回值的方式,这可能是更好的方法。

你想要的是不可能的,因为你试图混合编译时(模板)和运行时(地图查找)代码。

您要么必须使其完全运行时:

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

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