C ++ 11 лямбда как переменная-член? - PullRequest
42 голосов
/ 06 июля 2011

Можно ли определить лямбда-члены как члены класса?

Например, можно ли переписать приведенный ниже пример кода, используя лямбду вместо функционального объекта?

struct Foo {
    std::function<void()> bar;
};

ПричинаИнтересно, потому что следующие лямбда-выражения могут быть переданы в качестве аргументов:

template<typename Lambda>
void call_lambda(Lambda lambda) // what is the exact type here?
{ 
    lambda();
}

int test_foo() {
    call_lambda([]() { std::cout << "lambda calling" << std::endl; });
}

Я подумал, что если лямбда-выражение можно передать в качестве аргумента функции, то, возможно, они также могут быть сохранены как переменная-член.

После еще нескольких попыток я обнаружил, что это работает (но это бессмысленно):

auto say_hello = [](){ std::cout << "Hello"; };
struct Foo {
    typedef decltype(say_hello) Bar;
    Bar bar;
    Foo() : bar(say_hello) {}
};

Ответы [ 5 ]

38 голосов
/ 06 июля 2011

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

#include <functional>
#include <cmath>

struct Example {

  Example() {
    lambda = [](double x) { return int(std::round(x)); };
  };

  std::function<int(double)> lambda;

};
17 голосов
/ 07 июля 2011

Шаблоны делают это возможным без стирания типа, но это так:

template<typename T>
struct foo {
    T t;
};

template<typename T>
foo<typename std::decay<T>::type>
make_foo(T&& t)
{
    return { std::forward<T>(t) };
}

// ...
auto f = make_foo([] { return 42; });

Повторение аргументов, которые все уже представили: []{} не является типом, поэтому вы не можете использовать его как, например,параметр шаблона, как вы пытаетесь.Использование decltype также сомнительно, потому что каждый экземпляр лямбда-выражения является нотацией для отдельного объекта замыкания с уникальным типом.(например, тип f выше , а не foo<decltype([] { return 42; })>.)

13 голосов
/ 12 мая 2014

Немного поздно, но я нигде не видел этот ответ. Если лямбда не имеет аргументов захвата, то она может быть неявно приведена к указателю на функцию с такими же аргументами и типами возврата.

Например, следующая программа прекрасно компилируется и делает то, что вы ожидаете:

struct a {
    int (*func)(int, int);
};

int main()
{
    a var;
    var.func = [](int a, int b) { return a+b; };
}

Конечно, одним из главных преимуществ лямбд является условие захвата, и как только вы его добавите, этот трюк просто не сработает. Используйте std :: function или шаблон, как указано выше.

10 голосов
/ 06 июля 2011
#include <functional>

struct Foo {
    std::function<void()> bar;
};

void hello(const std::string & name) {
    std::cout << "Hello " << name << "!" << std::endl;
}

int test_foo() {
    Foo f;
    f.bar = std::bind(hello, "John");

    // Alternatively: 
    f.bar = []() { hello("John"); };
    f.bar();
}
3 голосов
/ 06 июля 2011

"если лямбда может быть передана как аргумент функции, то, возможно, также как переменная-член"

Первый вариант - да, вы можете использовать для этого вывод аргументов шаблона или «авто». Второе, вероятно, нет, так как вам нужно знать тип в точке объявления, и ни один из предыдущих двух приемов не может быть использован для этого.

Тот, кто может работать, но для которого я не знаю, будет ли он, использует decltype.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...