Как преобразовать std :: map в std :: function? - PullRequest
0 голосов
/ 28 мая 2018

A std::map<K,V> реализует частичную функцию типа std::function<V(K)>.

Я пытаюсь реализовать универсальную функцию 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];
    };
}

Мои вопросы:

  • Имеются ли аналогичные функции в STL для C ++ 11?
  • Если нет, то как я могу реализовать их с C ++ 11?

1 Ответ

0 голосов
/ 28 мая 2018

Имеется ли аналогичная функциональность в STL для C ++ 11?

Нет, насколько я знаю.

Но сам std::map«похожая функциональность доступна в STL для C ++ 11» (а также 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, можно упростить следующим образом:

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 () не реализован).

Вы можете избежать этой проблемы, используя SFINAE, включив функцию только (на примере), если *Контейнер 1032 * определяет тип mapped_type;Я имею в виду

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