c ++模板化地图,不同类型参数的通用接口

时间:2016-05-22 19:31:54

标签: c++ templates parameters stdmap

我有参数类,它包含不同类型的参数。

  std::map<std::string, std::string >        _params_string;
  std::map<std::string, int    >             _params_int;
  std::map<std::string, double      >        _params_double;
  std::map<std::string, bool        >        _params_bool;

我想有一个方法,用户可以将参数设置为:

  template<class type>
  inline void set(const std::string &key, const type &value)
  {
      _params[key] = value;
  }

但是,由于我对不同类型的参数有不同的存储空间,因此它变得一团糟。

对于不同类型的参数,是否有人对共同接口/存储有任何建议?

3 个答案:

答案 0 :(得分:1)

您可以使用像Boost.Variant这样的歧视联盟将所有地图缩小为:

using Parameter = boost::variant<int, double, bool, std::string>;
std::map<std::string, Parameter> _params;

现在你只有一张地图,你(显然)只需要一个set()

template <class T>
void set(std::string const& key, T const& value) {
    _params[key] = value;
}

每个参数都会知道它所持有的类型。这另外解决了在多个地图中存在相同密钥的问题 - 因为这没有多大意义。

答案 1 :(得分:0)

我可以看到几种方法来做到这一点。但是我能想到的最简单的一个需要C ++ 14的支持。

Tuples,C ++ 14

template <typename T>
using stringmap = std::map<std::string, T>;

std::tuple<stringmap<std::string>, stringmap<std::int>, stringmap<std::double>, stringmap<std::bool>> _params;

template <typename T>
explicit void set(const std::string & key, const T & value) {
    std::get<stringmap<T>>(_params)[key] = value;
}

您可以使用get进行类似的舞蹈,并且您始终可以使用std::get<stringmap<T>>(_params)为特定类型引用所选地图。

Tuples,C ++ 11

只要您愿意在可以按类型索引的元组上编写get例程,就可以以相同的方式执行此操作。这是我写的一个叫tget

template <std::size_t Pos, std::size_t Count, typename T, typename... Rest>
struct _tget_tuple_helper {
    static constexpr auto pos = Pos;
    static constexpr auto count = Count;
};

template <std::size_t Pos, std::size_t Count, typename T, typename S, typename... Rest>
struct _tget_tuple_helper<Pos, Count, T, S, Rest...> {
    static constexpr auto match = std::is_same<T, typename std::decay<S>::type>::value;
    using parent = _tget_tuple_helper<Pos + 1, match ? Count + 1 : Count, T, Rest...>;
    static constexpr auto pos = match ? Pos : parent::pos;
    static constexpr auto count = parent::count;
};

template <typename T, typename... Types>
using tget_tuple_helper = _tget_tuple_helper<0, 0, typename std::decay<T>::type, Types...>;

template <typename T, typename... Types>
constexpr
typename std::enable_if<tget_tuple_helper<T, Types...>::count == 1, T &>::type
tget(std::tuple<Types...> & t) {
    return std::get<tget_tuple_helper<T, Types...>::pos>(t);
}
template <typename T, typename... Types>
constexpr
typename std::enable_if<tget_tuple_helper<T, Types...>::count == 1, const T &>::type
tget(const std::tuple<Types...> & t) {
    return std::get<tget_tuple_helper<T, Types...>::pos>(t);
}

使用此功能,您可以在C ++ 14示例中将std::get替换为tget。其他一切都应该是一样的。

答案 2 :(得分:0)

您可以尝试使用任何类型的此类std::map<std::string,std::experimental::any>

链接:c++ 17 any type