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];
};
}
Мои вопросы:
@ Jarod42 Что касается моего текущего уровня обучения: нет, это не намеренно.
@ziggystar - ответ улучшен (после комментария Jarod42).





Is there a similar functionality available in the STL for C++11?
Нет, насколько я знаю.
Но сам std::map - это «аналогичный функционал, доступный в STL для C++ 11» (а также C++ 98), ИМХО.
If not, how can I implement it with 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, включив функцию только (в качестве примера), если контейнер C определяет тип 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;
}
опередить меня :(
@UmNyobe - извините :-)
Первый способ также позволит std::unordered_map без дополнительной перегрузки, кстати.
@ Jarod42 - Вы правы; но шаблоны-шаблоны и вариативные шаблоны могут помочь. Ответ изменен. Спасибо!
Теперь вы принимаете std::vector, даже если у вас будет ошибка внутри функции.
@ Jarod42 - да ... очень уродливая ошибка ... добавлена версия с поддержкой SFINAE для перехвата только типов с mapped_type внутри ... но теперь моя упрощенная версия сложнее оригинальной OP :(
Я бы остановился на конкретных версиях для std::map / std::unordered_map, которые являются наиболее читаемыми и в большинстве случаев их должно хватить.
Это намеренно возвращаемое значение, а не ссылка? Разрешено ли изменять карту намеренно?