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
Шаблони також можуть покращити розмір кеш-пам’яті, усуваючи переходи до загального нелокального коду (у цьому випадку виконуйте свою лямбду безпосередньо, без необхідності переходити через загальну std::functionобгортку спочатку)
jalf

5
Ця цитата, "якщо об'єкт лямбда-функції досить малий, він може бути представлений в std::functionоб'єкті в рядку " , вводить в оману. Лямбди завжди доступні для вбудованого (компілятор, звичайно, може не робити). std::functionреалізації зазвичай використовують оптимізацію невеликих об’єктів, щоб уникнути розподілу купи. Якщо лямбда має досить невеликий список захоплення, він буде зберігатися std::functionбез використання купи. Окрім того, що розмір лямбди не має реального значення.
deft_code

2
@bdonlan: До речі, чому там &в void f(F & lambda)?
Nawaz

2
@bdonlan: Але const & припускає, що члени лямбда (захоплення за значеннями) не можуть бути змінені. Що може бути не тим, що хоче користувач.
Nicol Bolas

2
@bdonlan Минув деякий час, але передача як посилання, що не є const, не дозволяє побудувати тимчасову лямбда у виклику функції. Тут найкращим буде посилання на значення 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 ::


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

1
Щиро дякую за це!
Майк Лі

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.