2

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.)

9
  • 1
    you cannot initialize the member in the body of the constructor. It is initialized before the body of the constructor is executed. Commented Sep 8, 2021 at 10:49
  • I see, so how can I set the f to be the same as _f inside the body, after the checks I have to do? Commented Sep 8, 2021 at 10:51
  • I dont quite understand your motivation. What kind of checks can you do with the second version of the code that you cannot do with the first? Commented Sep 8, 2021 at 10:51
  • 2
    sounds like a xy problem. Your complete code will have more issues because each lamda expression has a unique type. Maybe ask for the actual problem you are trying to solve, but consider that this question already has an answer, so perhaps open a new one Commented Sep 8, 2021 at 10:54
  • 1
    you could use SFINAE to check the right signature, then initializing the lambda in the initializer list is fine. Commented Sep 8, 2021 at 10:56

2 Answers 2

5

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).

Sign up to request clarification or add additional context in comments.

2 Comments

it will compile, but I am not sure if it achieves what OP wants to achieve by that modification of their code
@463035818_is_not_a_number Yes, it depends on how the check is performed and what should be performed when check fails.
0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.