C++11 lambda as member variable?

C++C++11Lambda

C++ Problem Overview


Can lambda's be defined as class members?

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

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

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

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.

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

C++ Solutions


Solution 1 - C++

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

#include <functional>
#include <cmath>

struct Example {

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

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

};

Solution 2 - C++

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 decltype is 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 f above is not foo<decltype([] { return 42; })>.)

Solution 3 - C++

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.

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.

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

Solution 5 - C++

As long as lambda is constant (without closures), you can do something like this:

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

https://godbolt.org/z/W5K1rexv3

Or we can apply deduction guides to make it work for all lambdas:

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

https://godbolt.org/z/cenrzTbz4

Solution 6 - C++

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

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStackedCrookedView Question on Stackoverflow
Solution 1 - C++wjlView Answer on Stackoverflow
Solution 2 - C++Luc DantonView Answer on Stackoverflow
Solution 3 - C++Shachar ShemeshView Answer on Stackoverflow
Solution 4 - C++Alexandre C.View Answer on Stackoverflow
Solution 5 - C++KonardView Answer on Stackoverflow
Solution 6 - C++dascandyView Answer on Stackoverflow