ziggystar
ziggystar

Reputation: 28680

How to convert a std::map to a std::function?

A std::map<K,V> implements a partial function of type std::function<V(K)>.

I am trying to implement a generic function map2fun() that turns a std::map into a std::function object.

The following does not compile:

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

My questions are:

Upvotes: 3

Views: 110

Answers (1)

max66
max66

Reputation: 66200

Is there a similar functionality available in the STL for C++11?

No, as far I know.

But the std::map itself is "a similar functionality available in the STL for C++11" (and also C++98), IMHO.

If not, how can I implement it with C++11?

Adding some typename's to your code, by example

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

But I find clearer this way

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

but, as pointed by Jarod42 (thanks!), this intercept std::map only (not std::unordered_map, not similar (also custom) types), so you can make it more flexyble as follows

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

and, starting from C++17, con be simplified as follows

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

As pointer by Jarod42 (thanks again!) this template-template version is enabled also for other containers (std::vector, by example) and this give a very ugly error message (not the plain and simple "map2fun() not implemented).

You can avoid this problem, using SFINAE, enabling the function only (by example) if the C container define a mapped_type type; I mean

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

But now my simpler version is more complicated that your original one :( .

The following is a full working double example

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

Upvotes: 4

Related Questions