Запишите функцию, которая принимает лямбда-выражение как аргумент

У меня есть метод как это

template<typename T, typename U>
map<T,U> mapMapValues(map<T,U> old, T (f)(T,U))
{
    map<T,U> new;
    for(auto it = old.begin(); it != old.end(); ++it)
    {
        new[it->first] = f(it->first,it->second);
    }
    return new; 
}

и идея состоит в том, что Вы назвали бы его как это

BOOST_AUTO_TEST_CASE(MapMapValues_basic)
{
    map<int,int> test;
    test[1] = 1;
    map<int,int> transformedMap = VlcFunctional::mapMapValues(test, 
        [&](int key, int value) -> int
        {
            return key + 1; 
        }
    );
}

Однако я получаю ошибку: никакой экземпляр шаблона функции "VlcFunctional:: mapMapValues" соответствует типам аргумента списка аргументов: (станд.:: карта, станд.:: средство выделения>>, __ lambda1)

Какая-либо идея, что я делаю неправильно? Visual Studio 2008 и компилятор Intel C ++ 11.1

36
задан adl 21 February 2012 в 15:20
поделиться

3 ответа

Ваша функция ожидает указатель на функцию, а не лямбду.

В C ++, как правило, существует 3 типа «вызываемых объектов».

  1. Указатели на функции.
  2. Функциональные объекты.
  3. Лямбда-функции.

Если вы хотите иметь возможность использовать все это в интерфейсе вашей функции, вы можете использовать std :: function :

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T, U)> f)
{
    ...
}

Это позволит вызывать функцию с использованием любого из трех типы вызываемых объектов выше. Однако плата за это удобство заключается в небольших накладных расходах на вызовы функции (обычно проверка нулевого указателя, затем вызов через указатель функции). Это означает, что функция почти наверняка не встроена (за исключением, возможно, расширенного WPO / LTO ).

В качестве альтернативы, вы можете добавить дополнительный параметр шаблона, чтобы принять произвольный тип для второго параметра. Это будет более эффективно, но вы потеряете безопасность типов для используемой функции и может привести к еще большему раздутию кода.

template<typename T, typename U, typename F> 
map<T,U> mapMapValues(map<T,U> old, F f) 
39
ответ дан 27 November 2019 в 05:49
поделиться

Объявление типа вашего параметра T (f) (T, U) относится к свободной функции типа, принимающей T и U и возвращающей Т '. Вы не можете передать ему лямбду, объект функции или что-то еще, кроме фактической функции с этой подписью.

Вы можете решить эту проблему, изменив тип параметра на std :: function следующим образом:

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T,U)>)
{
}

В качестве альтернативы вы можете объявить тип функции как шаблон аргумент вроде этого:

template<typename T, typename U, typename Fn> 
map<T,U> mapMapValues(map<T,U> old, Fn fn)
{
  fn(...);
}
12
ответ дан 27 November 2019 в 05:49
поделиться

Лямбда-выражения с пустым списком захвата должны распадаться на указатели функций, согласно n3052 . Однако кажется, что эта функция не реализована в VC ++ и лишь частично в g ++, см. Мой вопрос SO .

5
ответ дан 27 November 2019 в 05:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: