如何在 C++11 中将 lambda 表达式存储为类的字段?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9186510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:26:45  来源:igfitidea点击:

How can I store a lambda expression as a field of a class in C++11?

c++classlambdac++11field

提问by templatetypedef

I'd like to create a class where the client can store a lambda expression like []() -> void {}as a field of the class, but I can't figure out how to do so. One answer suggested using decltype, which I tried with no success. Here is a ideone source link. The below is the source and result:

我想创建一个类,客户端可以在其中将 lambda 表达式存储为类[]() -> 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");
   });
}

Result:

结果:

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&)

Does anyone know how to do this?

有谁知道如何做到这一点?

回答by templatetypedef

If you want a class member to be a lambda expression, consider using the std::function<>wrapper type (from the <functional>header), which can hold any callable function. For example:

如果您希望类成员成为 lambda 表达式,请考虑使用std::function<>包装器类型(来自<functional>标头),它可以容纳任何可调用函数。例如:

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

This way, you don't need to know the type of the lambda expression. You can just store a std::function<>of the appropriate function type, and the template system will handle all the types for you. More generally, any callable entity of the appropriate signature can be assigned to a std::function<>, even if the the actual type of that functor is anonymous (in the case of lambdas) or really complicated.

这样,您就不需要知道 lambda 表达式的类型。你可以只存储一个std::function<>合适的函数类型,模板系统会为你处理所有类型。更一般地,任何具有适当签名的可调用实体都可以分配给 a std::function<>,即使该函子的实际类型是匿名的(在 lambdas 的情况下)或非常复杂。

The type inside of the std::functiontemplate should be the function type corresponding to the function you'd like to store. So, for example, to store a function that takes in two ints and returns void, you'd make a std::function<void (int, int)>. For a function that takes no parameters and returns an int, you'd use std::function<int()>. In your case, since you want a function that takes no parameters and returns void, you'd want something like this:

std::function模板里面的类型应该是你想要存储的函数对应的函数类型。因此,例如,要存储一个接受两个ints 并返回 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.
}

Hope this helps!

希望这可以帮助!

回答by cubuspl42

The only way I can think of to store a lambda in a class is to use a template with a helper make_function:

我能想到的在类中存储 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");
    });
}