Reputation: 771
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
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
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