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

Sta*_*ked 45 c++ lambda c++11

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

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

struct Foo {
    std::function<void()> bar;
};
Run Code Online (Sandbox Code Playgroud)

我想知道的原因是因为以下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; });
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

wjl*_*wjl 38

lambda只是一个函数对象,所以,是的,你可以使用lambda初始化一个函数成员.这是一个例子:

#include <functional>
#include <cmath>

struct Example {

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

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

};
Run Code Online (Sandbox Code Playgroud)

  • 为什么不使用初始化列表? (5认同)
  • 我没有故意将函数放在我的示例中的初始化列表中,因为我认为如果你真的在真实情况下做了类似上面的事情,你的lambda实际上会做捕获或更复杂的地方它在初始化列表中没有意义.但是当然你可以做这个`Example():lambda([](double x){return int(std :: round(x));}){}`如果你想要的话.=) (5认同)
  • Lambda 不会创建 `std::function&lt;...&gt;` 对象。也就是说,它们可以隐式转换为 1。有几个重要的区别。首先,lambda 不进行堆分配,但 std::function 会进行堆分配。没有任何捕获的 Lambda 实际上是普通函数类型(例如“void (&amp;)(int, char)”)。 (2认同)

Luc*_*ton 19

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

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; });
Run Code Online (Sandbox Code Playgroud)

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

  • 就我而言,重要的是数组中的所有函数都具有相同的参数和返回类型,因此 vanilla std::function 工作得很好。我仍然想知道开销 (2认同)

Sha*_*esh 13

有点晚了,但我没有在这里找到这个答案.如果lambda没有捕获参数,那么它可以隐式地转换为指向具有相同参数和返回类型的函数的指针.

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

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

int main()
{
    a var;
    var.func = [](int a, int b) { return a+b; };
}
Run Code Online (Sandbox Code Playgroud)

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


Ale*_* C. 11

#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();
}
Run Code Online (Sandbox Code Playgroud)


Kon*_*ard 5

只要 lambda 是常数(没有闭包),你就可以这样做:

#include <iostream>

template<auto function>
struct Foo
{
    decltype(function) bar = function;
};

void call_lambda(auto&& lambda)
{
    lambda();
}

int main()
{
    Foo<[](){ std::cout << "Hello"; }> foo;
    foo.bar();
    call_lambda(foo.bar);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/W5K1rexv3

或者我们可以应用推导指南使其适用于所有 lambda:

#include <iostream>

template<typename T>
struct Foo 
{
    T bar;
};

template<typename T>
Foo(T) -> Foo<std::decay_t<T>>;

void call_lambda(auto&& lambda)
{
    lambda();
}

int main()
{
    std::string hello = "Hello";
    Foo foo([&](){ std::cout << hello; });
    foo.bar();
    call_lambda(foo.bar);
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/cenrzTbz4