【问题标题】:single get method which return different type variables返回不同类型变量的单个 get 方法
【发布时间】:2012-06-11 19:44:14
【问题描述】:

我想创建一个类,它有一个 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 函数,我传递我想要的变量名,该函数会将它返回给我。

【问题讨论】:

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


    【解决方案1】:

    另一种解决方案是将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 是有原因的 :)

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

          你要么必须让它完全运行:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-09-28
            • 1970-01-01
            • 2012-05-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多