c ++ 0x: правильный способ получить лямбда в качестве параметра по ссылке


85

Как правильно определить функцию, которая получает int->intпараметр лямбда по ссылке?

void f(std::function< int(int) >& lambda);

или же

void f(auto& lambda);

Я не уверен, что последняя форма является допустимым синтаксисом.

Есть ли другие способы определения лямбда-параметра?


10
Зачем вам лямбда по ссылке? Вы имеете в виду const&?
deft_code

Ответы:


84

У вас не может быть autoпараметра. В основном у вас есть два варианта:

Вариант №1: Используйте, std::functionкак вы показали.

Вариант №2: Используйте параметр шаблона:

template<typename F>
void f(F &lambda) { /* ... */}

Вариант №2 в некоторых случаях может быть более эффективным, поскольку он позволяет избежать потенциального выделения кучи для встроенного объекта лямбда-функции, но он возможен только в том случае, если fего можно поместить в заголовок как функцию шаблона. Это также может увеличить время компиляции и объем I-cache, как и любой шаблон. Обратите внимание, что это также может не иметь никакого эффекта, поскольку, если объект лямбда-функции достаточно мал, он может быть представлен встроенным в std::functionобъект.


1
Шаблоны также могут улучшить объем I-кеша, устраняя переходы к общему нелокальному коду (в этом случае выполняйте лямбду напрямую, без необходимости std::functionсначала переходить через универсальную оболочку)
jalf

5
Эта цитата, «если объект лямбда-функции достаточно мал, он может быть представлен встроенным в std::functionобъект» , вводит в заблуждение. Лямбды всегда доступны для встраивания (компилятор, конечно, может этого не делать). std::functionреализации обычно используют оптимизацию малых объектов, чтобы избежать выделения кучи. Если лямбда-выражение имеет достаточно маленький список захвата, он будет сохранен std::functionбез использования кучи. В остальном размер лямбды не имеет реального значения.
deft_code

2
@bdonlan: Кстати, почему там &в void f(F & lambda)?
Nawaz

2
@bdonlan: Но const & предполагает, что члены лямбда (значения захвата) не могут быть изменены. Что может быть не тем, чего хочет пользователь.
Никол Болас

2
@bdonlan Прошло время, но передача неконстантной ссылки не позволяет создавать временную лямбду в вызове функции. Здесь лучше всего подойдет ссылка на r-значение.
zennehoy

46

Я бы использовал templateкак:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

Вывод:

500
1000
100

Демо: http://www.ideone.com/EayVq


13

Я знаю, что прошло 7 лет, но вот способ, о котором больше никто не упоминал:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

Какие выходы:

foo
lambda 1

Нет необходимости в шаблонах или std :: function


12
это ограничено только лямбдами, которые могут распадаться на указатели функций (лямбды без захвата), а также требует указания точной сигнатуры (как и для std::functioncase), в то время как шаблонная версия не имеет этого ограничения.
Андрей Тыличко

Большое вам спасибо за это!
Майк Ли

1

void f(auto& lambda);

Это близко. Фактически будет компилироваться:

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.