Подтвердить что ты не робот

Как сохранить лямбда-выражение как поле класса в С++ 11?

Я хотел бы создать класс, в котором клиент может хранить лямбда-выражение, например []() -> void {}, как поле класса, но я не могу понять, как это сделать. Один ответ предложил использовать decltype, который я пробовал без успеха. Вот ссылка источника ideone. Ниже приведен источник и результат:

#include <cstdio>
auto voidLambda = []()->void{};

class MyClass {
public:
     decltype(voidLambda) t;
     MyClass(decltype(voidLambda) t) { 
        this->t = t;
     }
};

int main() {
   MyClass([] {
      printf("hi");
   });
}

Результат:

prog.cpp: In constructor 'MyClass::MyClass(<lambda()>)':
prog.cpp:3:79: error: no matching function for call to '<lambda()>::__lambda0()'
prog.cpp:2:20: note: candidates are: <lambda()>::<lambda>(const<lambda()>&)
prog.cpp:2:20: note:                 <lambda()>::<lambda>(<lambda()>&&)
prog.cpp:3:88: error: no match for 'operator=' in '((MyClass*)this)->MyClass::t = t'
prog.cpp: In function 'int main()':
prog.cpp:5:27: error: no matching function for call to 'MyClass::MyClass(main()::<lambda()>)'
prog.cpp:3:48: note: candidates are: MyClass::MyClass(<lambda()>)
prog.cpp:3:14: note:                 MyClass::MyClass(const MyClass&)

Кто-нибудь знает, как это сделать?

4b9b3361

Ответ 1

Если вы хотите, чтобы член класса был лямбда-выражением, рассмотрите использование типа оболочки std::function<> (из заголовка <functional>), который может содержать любую вызываемую функцию. Например:

std::function<int()> myFunction = []() { return 0; }
myFunction(); // Returns 0;

Таким образом, вам не нужно знать тип выражения лямбда. Вы можете просто сохранить std::function<> соответствующего типа функции, и система шаблонов будет обрабатывать все типы для вас. В более общем плане любой вызываемый объект соответствующей сигнатуры может быть назначен std::function<>, даже если фактический тип этого функтора является анонимным (в случае lambdas) или действительно сложным.

Тип внутри шаблона std::function должен быть типом функции, соответствующим функции, которую вы хотите сохранить. Так, например, чтобы сохранить функцию, которая принимает два int и возвращает void, вы должны сделать std::function<void (int, int)>. Для функции, которая не принимает никаких параметров и возвращает int, вы должны использовать std::function<int()>. В вашем случае, поскольку вам нужна функция, которая не принимает никаких параметров и возвращает void, вам нужно что-то вроде этого:

class MyClass { 
public:
    std::function<void()> function;
    MyClass(std::function<void()> f) : function(f) {
        // Handled in initializer list
    }
};

int main() {
    MyClass([] {
        printf("hi")
    }) mc; // Should be just fine.
}

Надеюсь, это поможет!

Ответ 2

Единственный способ, с помощью которого я могу хранить lambda в классе, - использовать шаблон со вспомогательной функцией make_:

#include <cstdio>
#include <utility>

template<class Lambda>
class MyClass {
    Lambda _t;
public:
    MyClass(Lambda &&t) : _t(std::forward<Lambda>(t)) {
        _t();
    }
};

template<class Lambda>
MyClass<Lambda> make_myclass(Lambda &&t) {
    return { std::forward<Lambda>(t) };
}

int main() {
    make_myclass([] {
        printf("hi");
    });
}