【问题标题】:Type-safe composition of maps in C++C++ 中映射的类型安全组合
【发布时间】:2021-03-30 02:11:32
【问题描述】:

我想用 C++ 编写一个类型安全的函数来组成任意数量的映射。我通过编写一个辅助函数point 来计算组合在某个点的应用——

template <typename K>
const K& point(const K& k) {
  return k;  // recursive base-case.
}

template<typename K, typename V, typename ... Ts>
auto point(const K& k, const std::map<K, V>& map, Ts... maps) {
  return point(map.at(k), maps...);
}

这使得compose 的逻辑简单明了:

template <typename K, typename V, typename ... Ts>
auto compose(const std::map<K, V>& map, Ts... maps) {

  using U = typename std::result_of<point(V, Ts...)>::type;  // <- problem

  std::map<K, U> composition;
  for (const auto& [k, v] : map)
    composition[k] = point(v, maps...);
  return composition;
}

我唯一的问题是推导U,结果映射的值类型。我确信std::result_of 是一种合适的方法,但我通过上面的代码得到error: 'V' does not refer to a value。我也尝试过使用decltype(point&lt;V, Ts...&gt;()),但这给出了error: no matching function for call to 'point'

示例用法:

std::map<int, std::string> m1;
m1[0] = "a";
m1[1] = "b";
 
std::map<std::string, float> m2;
m2["a"] = 3.0;
m2["c"] = 4.0;
 
std::map<float, std::string> m3;
m3[3.0] = "three";
m3[4.0] = "four";

auto composition = compose(m1, m2, m3);

【问题讨论】:

  • “point”的返回值不是一直都是“const K&”吗?如果是这样,您可以避免出现问题。
  • point 是一个模板函数,它的返回类型取决于它的模板参数。
  • 我认为你可以改用using U = decltype(point(std::declval&lt;V&gt;(), std::decval&lt;Ts&gt;()...)); 来让它工作
  • 感谢@NathanOliver,这行得通!我要花很长时间才能弄清楚...
  • 记住还要在point()的递归版本之前声明递归基础案例。

标签: c++ variadic-templates return-type-deduction


【解决方案1】:

这是我使用@NathanOliver 提供的类型推导并使用std::optional 省略任何无法通过组合完全映射的元素的最终版本。

template<typename K>
const K& point(const K& k) { return k; }

template<typename K, typename V, typename ... Ts>
auto point(const K &k, const std::map<K, V>& map, Ts... maps) {
  return map.find(k) == map.end() ?
    std::nullopt :
    std::optional(point(map.at(k), maps...));
}

template<typename K, typename V, typename ... Ts>
auto compose(const std::map<K, V>& map, Ts... maps) {
  using U = typename decltype(point(std::declval<V>(), std::declval<Ts>()...))::value_type;
  std::map<K, U> composition;
  for (const auto& [k, v] : map) {
    auto result = point(v, maps...);
    if (result.has_value())
      composition[k] = result.value();
  }
  return composition;
}

【讨论】:

  • 稍微简化一下:在decltype()里面,你可以写maps...,而不是std::declval&lt;Ts&gt;()...
  • 另一个未经请求的建议:不要混合类型和值的名称:可能有效但容易出错。我的意思是:不要命名map 一个值;尤其是当类型为map.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多