【问题标题】:How to convert a std::map to a std::function?如何将 std::map 转换为 std::function?
【发布时间】:2018-11-06 23:15:02
【问题描述】:

std::map<K,V> 实现了 std::function<V(K)> 类型的 partial 函数。

我正在尝试实现一个通用函数map2fun(),它将std::map 转换为std::function 对象。

以下内容无法编译:

template<typename M>
function<M::mapped_type(M::key_type)> map2fun(M& m)
{
  return [&m](M::key_type k)
    {
      return m[k];
    };
}

我的问题是:

  • 在 C++11 的 STL 中是否有类似的功能可用?
  • 如果没有,如何用 C++11 实现?

【问题讨论】:

  • 是否有意返回值而不是引用?是否有意允许修改地图?
  • @Jarod42 就我目前的学习情况而言:不,不是故意的。
  • @ziggystar - 改进了答案(根据 Jarod42 的评论)。

标签: c++ c++11 templates lambda stl


【解决方案1】:

C++11 的 STL 中是否有类似的功能可用?

没有,据我所知。

std::map 本身是“在 C++11 的 STL 中可用的类似功能”(以及 C++98),恕我直言。

如果没有,如何用 C++11 实现?

通过示例将一些typename 添加到您的代码中

template <typename M>
std::function<typename M::mapped_type(typename M::key_type)> map2fun (M & m)
 { return [&m](typename M::key_type k) { return m[k]; }; }

但我觉得这样更清楚

template <typename K, typename V>
std::function<V(K)> m2f2 (std::map<K, V> & m)
 { return [&m](K k) { return m[k]; }; }

但是,正如 Jarod42 所指出的(谢谢!),这个拦截 std::map 只(不是 std::unordered_map,不是类似(也是自定义)类型),所以你可以使它更灵活如下

template <template <typename ...> class C, typename K, typename V,
          typename ... Ts>
std::function<V(K)> m2f2 (C<K, V, Ts...> & m)
 { return [&m](K k) { return m[k]; }; }

并且,从 C++17 开始,con 简化如下

template <template <typename ...> class C, typename K, typename V>
std::function<V(K)> m2f2 (C<K, V> & m)
 { return [&m](K k) { return m[k]; }; }

作为 Jarod42 的指针(再次感谢!)这个模板模板版本也适用于其他容器(std::vector,例如),这给出了一个非常丑陋的错误消息(不是简单明了的“map2fun() 不是实施)。

如果C 容器定义了mapped_type 类型,您可以使用SFINAE 避免此问题,仅启用该功能(通过示例);我是说

template <template <typename ...> class C, typename K, typename V,
          typename ... Ts, typename = typename C<K, V, Ts...>::mapped_type>
std::function<V(K)> m2f2 (C<K, V, Ts...> & m)
 { return [&m](K k) { return m[k]; }; }

但现在我更简单的版本比你原来的更复杂:(。

以下是一个完整的工作双示例

#include <map>
#include <iostream>
#include <functional>
#include <unordered_map>

template <typename M>
std::function<typename M::mapped_type(typename M::key_type)> m2f1 (M & m)
 { return [&m](typename M::key_type k) { return m[k]; }; }

template <template <typename ...> class C, typename K, typename V,
          typename ... Ts, typename = typename C<K, V, Ts...>::mapped_type>
std::function<V(K)> m2f2 (C<K, V, Ts...> & m)
 { return [&m](K k) { return m[k]; }; }

int main ()
 {
   std::map<int, long> m1 {{0, 1L}, {1, 2L}, {2, 4L}, {3, 8L}};
   std::unordered_map<int, long> m2 {{0, 1L}, {1, 2L}, {2, 4L}, {3, 8L}};

   auto l1 { m2f1(m1) };
   auto l2 { m2f2(m2) };
   auto l3 { m2f1(m1) };
   auto l4 { m2f2(m2) };

   std::cout << l1(2) << std::endl;
   std::cout << l2(2) << std::endl;
   std::cout << l3(2) << std::endl;
   std::cout << l4(2) << std::endl;
 }

【讨论】:

  • 击败我 :(
  • @UmNyobe - 抱歉 :-)
  • 第一种方式也允许std::unordered_map 没有额外的过载顺便说一句。
  • @Jarod42 - 你是对的;但是模板模板和可变参数模板可以提供帮助。答案已修改。谢谢!
  • 您现在接受std::vector,即使您在函数内部会出错。
猜你喜欢
  • 2014-12-11
  • 2012-06-25
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多