Home > OS >  Variable type of template lambda (C )
Variable type of template lambda (C )

Time:10-12

I'm implementing a lambda as variable. In C 20 it works this way:

auto lambda = []<typename T>() -> const T& {
   ...
};

Now I want to store this kind of lambda function as a member variable of a struct:

struct A {
    ??? m_lambda;
    A(??? lambda) : m_lambda(lambda) {}
};

Is there a way to do this?

CodePudding user response:

You store any templated lambda the same ugly way you store ordinary ones:

constexpr auto lambda = []<typename T>() {};

struct Foo{
    decltype(lambda) m_lambda;
    Foo():m_lambda(lambda){}
};

This works because it is operator() that is actually templated, not the automatically-generated lambda type.

If you do not rely on inlining any calls to the lambda (for performance), you can store it in std::function<Ret(Args)> for correct signature.

std::function is also the only* option if the lambda cannot be defined before Foo as seems to be the case of your constructor.

struct A {
    std::function<void()> m_lambda;
    // Not a lambda per se.
    A(std::function<void()> lambda) : m_lambda(std::move(lambda)) {}
};

The above is not a lambda exactly because it doesn't really make sense most of the time to take a lambda as parameter as each has a distinct type making the argument effectively redundant.

*One can always make A a class template and use CTAD for deduction, not sure you want to go that way though.

CodePudding user response:

In c 20 you can do:

struct Foo
{
    decltype([] <class T> () {/* ... */ }) m_lambda {};
};

That being said it doesn't make any sense to store a lambda as a data member. Lambdas cannot change so a method is the simple, preferred alternative.

CodePudding user response:

Since your lambda is templated, you will need to contain the lambda directly in your object.

Fortunately, it's quite easy to do in C 20 (and C 17):

auto lambda = []<typename T>() -> const T& {
   // ...
};

template<typename L> // <-- L is the lambda type
struct A {
    L m_lambda;
    A(L lambda) : m_lambda(lambda) {}

    void foo() {
        // Can call using many types using the template
        int const& a = m_lambda.template operator()<int>();
        float const& b = m_lambda.template operator()<float>();
    }
};

int main() {
    auto my_a = A{lambda}; // construct using the lambda and CTAD
    my_a.foo();
}

If on the contrary you need A to only call one version of the template, you can wrap the lambda in another lambda:

struct A {
    std::function<int const&()> m_lambda;

    A(auto const& lambda) : m_lambda{
        [lambda]{ return lambda.template operator()<int>(); }
    } {}

    void foo() {
        // Can call and get a int const reference back
        int const& a = m_lambda();
    }
};
  • Related