C++11 lambda 作为成员变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6601930/
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-28 20:24:28  来源:igfitidea点击:

C++11 lambda as member variable?

c++c++11lambda

提问by StackedCrooked

Can lambda's be defined as class members?

可以将 lambda 定义为类成员吗?

For example, would it be possible to rewrite the code sample below using a lambda instead of a function object?

例如,是否可以使用 lambda 而不是函数对象重写下面的代码示例?

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

The reason I wonder is because the following lambda's can be passed as arguments:

我想知道的原因是因为以下 lambda 可以作为参数传递:

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; });
}

I figured that if a lambda can be passed as a function argument then maybe they can also be stored as a member variable.

我想如果 lambda 可以作为函数参数传递,那么也许它们也可以存储为成员变量。

After more tinkering I found that this works (but it's kind of pointless):

经过更多的修补,我发现这有效(但它有点毫无意义):

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

采纳答案by Luc Danton

Templates make it possible without type erasure, but that's it:

模板可以在没有类型擦除的情况下实现,但就是这样:

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; });

Repeating the arguments that everyone has already exposed: []{}is not a type, so you can't use it as e.g. a template parameter like you're trying. Using decltypeis also iffy because every instance of a lambda expression is a notation for a separate closure object with a unique type. (e.g. the type of fabove is notfoo<decltype([] { return 42; })>.)

重复每个人已经公开的参数:[]{}不是一种类型,因此您不能将其用作例如您正在尝试的模板参数。Usingdecltype也是不确定的,因为 lambda 表达式的每个实例都是具有唯一类型的单独闭包对象的表示法。(例如f上面的类型不是foo<decltype([] { return 42; })>。)

回答by wjl

A lambda just makes a function object, so, yes, you can initialize a function member with a lambda. Here is an example:

一个 lambda 只是创建一个函数对象,所以,是的,你可以用一个 lambda 初始化一个函数成员。下面是一个例子:

#include <functional>
#include <cmath>

struct Example {

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

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

};

回答by Shachar Shemesh

A bit late, but I have not seen this answer anywhere here. If the lambda has no capture arguments, then it can be implicitly cast to a pointer to a function with the same arguments and return types.

有点晚了,但我在这里的任何地方都没有看到这个答案。如果 lambda 没有捕获参数,则可以将其隐式转换为指向具有相同参数和返回类型的函数的指针。

For example, the following program compiles fine and does what you would expect:

例如,以下程序可以正常编译并执行您期望的操作:

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

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

Of course, one of the main advantages of lambdas is the capture clause, and once you add that, then that trick will simply not work. Use std::function or a template, as answered above.

当然,lambdas 的主要优点之一是捕获子句,一旦添加了它,那么这个技巧就行不通了。使用 std::function 或模板,如上所述。

回答by Alexandre C.

#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();
}

回答by dascandy

"if a lambda can be passed as a function argument then maybe also as a member variable"

“如果 lambda 可以作为函数参数传递,那么也可以作为成员变量”

The first is a yes, you can use template argument deduction or "auto" to do so. The second is probably no, since you need to know the type at declaration point and neither of the previous two tricks can be used for that.

第一个是肯定的,您可以使用模板参数推导或“自动”来执行此操作。第二个可能不是,因为您需要知道声明点的类型,并且前两个技巧都不能用于此。

One that may work, but for which I don't know whether it will, is using decltype.

一种可能有效但我不知道它是否有效的方法是使用 decltype。