MaPo
MaPo

Reputation: 771

Initialize a lambda function in the body of a class constructor

I can compile the following code without any problem (using gcc 11.1.0):

#include <iostream>

template <typename Func>
class K {
    Func f;
public:
    K(Func _f): f{_f} {};
    void do_thing(int x) {f(x);};
};

int main()
{
    auto f = [](int x) {std::cout << x << std::endl;};
    K kl{f};
    kl.do_thing(5);

    return 0;
}

however I would like to perform some check in the constructor of the class K (for instance some std::is_convertible_v inside some bool function), so I tried to modify the code to

#include <iostream>

template <typename Func>
class K {
    Func f;
    
public:
    K(Func _f) {
    ...
    f = _f;};
    void do_thing(int x) {f(x);};
};

int main()
{
    auto f = [](int x) {std::cout << x << std::endl;};
    K kl{f};
    kl.do_thing(5);

    return 0;
}

which however gives me some error message

error: use of deleted function ‘main()::<lambda(int)>::<lambda>()’

and then

note: a lambda closure type has a deleted default constructor

This confuses me a lot since I cannot understand how it is possible that the former piece of code could compile since the lambda function has not default constructor.

Question
How can I set my f inside the body of the constructor? (This is just a MWE and in my case the class is a bit more complex and the checks I mentioned before make sense.)

Upvotes: 2

Views: 1132

Answers (2)

Pepijn Kramer
Pepijn Kramer

Reputation: 12849

Is this what you are looking for? It is the generic solution, not making any assumptions on the signature of Fn

#include <iostream>
#include <utility>

template <typename Fn>
class K
{
public:
    explicit K(const Fn& fn) :
        m_fn{ fn }
    {
    };

    template<typename... args_t>
    auto do_thing(args_t&&... args)
    {
        return m_fn(std::forward<args_t>(args)...);
    }

private:
    Fn m_fn;

};

int main()
{
    auto f = [](int x) {std::cout << x << std::endl; };
    K kl{ f };
    kl.do_thing(5);
}

Upvotes: 0

songyuanyao
songyuanyao

Reputation: 172894

How can I initialize my f inside the body of the constructor?

You can't. f = _f; inside the constructor body is assignment but not initialization. So f will be default-initialized firstly, then enter the constructor body (to perform assignment).

You might use std::function instead; which could be default-initialized, then you can assign it in constructor body.


BTW: Since C++20 your code will compile fine even it might not work as you expected (depending on the ... part). For lambdas,

If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).

Upvotes: 5

Related Questions