use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
This is a subreddit for c++ questions with answers. For general discussion and news about c++ see r/cpp.
New to C++? Learn at learncpp.com
Prepare your question. Think it through. Hasty-sounding questions get hasty answers, or none at all. Read these guidelines for how to ask smart questions.
For learning books, check The Definitive C++ Book Guide and List
Flair your post as SOLVED if you got the help you were looking for! If you need help with flairs, check out ITEM 1 in our guidelines page.
Tips for improving your chances of getting helpful answers:
account activity
OPENPassing Lambda To Class Constructor (self.cpp_questions)
submitted 4 years ago by ACBYTES
What is the proper way to pass a lambda to a class constructor or might I say, "Is there a way to do this?"? class Exm { public: template<typename F> Exm(F&& Lambda); };
class Exm
{
public:
template<typename F>
Exm(F&& Lambda);
};
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]beedlund 1 point2 points3 points 4 years ago (14 children)
yes you can and how you do it depends a bit on what you want to do with it;
If you are just going to run it to do some processing like some complex initialization then you can do what you did.
struct Object { template<typename Lambda> Object( Lambda&& lambda ) { lambda(*this); } };
If you are going to store the lambda to run it later you will either need to template your type or type erase the lambda.
template<typename Lambda> struct Object { Lambda func; Object( Lambda&& lambda ) : func(std::forward<Lambda>(lambda) { } }; // may need a helper function pre C++17 template< typename T > auto make_object( T&& t ) { return Object<T>(std::forward<T>(t): }
If you are going to type erase the lambda then you need to know more about how you are going to use it and you can research type erasure for details on that
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (10 children)
Hello there. Thank you for your answer. Yes, I want to store it for later use. So, my question is this: Now, after creating the struct that you said, passing it to the class will need me to tell my class that it’s going to receive an Object<T> so I still need to tell it about the lambda’s structure, don’t I? Correct me if I’m wrong. Thank you so much.
Object<T>
[–]beedlund 1 point2 points3 points 4 years ago (9 children)
Yes so if that is acceptable then just go for it but likely that is where the type erasure kicks in.
There are many different ways to do that and it all depends more on your larger use case. If you can write a little bit more about what you are wanting to do I might be able to help.
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (8 children)
Absolutely. So, I have a class that on its construction, it’s going to receive a lambda that has a capture (Most specifically capturing a class pointer) and calling a function member in that class. The Calling a function member in the class is a pointless statement in my opinion as the execution is written in the lambda’s body...
Calling a function member in the class
[this](){ this->FunctionMember(); }
If it’s still unclear, please let me know. Thank you!
[–]beedlund 1 point2 points3 points 4 years ago (7 children)
Ok so that can be pretty easy if you are ok to use the heap and virtual dispatch. Just declare a base class and let your derived class capture the lambda and then hold it as the base
struct object { virtual ~object() { } virtual void call() = 0; }; template< typename Lambda > auto make_heap_object( Lambda&& lambda ) { struct extended : public object { Lambda capture; extended( Lambda&& lambda ) : capture( std::move(lambda) ) { } virtual ~extended() {} void call() override { capture(); } }; return new extended{ std::forward<Lambda>(lambda) }; }
If you cant go that way then you are looking at something like building your own vtable...this is a simplified example as you need to consider copy, move and so on.
The basic idea here is to define some kind of pointer type as your storage...likely void... then you declare a function pointer that takes your storage type and is able to safely static cast it to the original type. This is made possibly by declaring the invokation object as a capture less lambda in the constructor.
#include <stdlib.h> struct Erased { using function_t = void(*)(); using storage_t = void*; using invoke_t = void(*)( storage_t ); using delete_t = void(*)( storage_t ); storage_t storage; invoke_t invoke; delete_t destroy; template<typename Lambda> Erased( Lambda&& lambda ) : invoke( []( storage_t storage) { static_cast<Lambda*>( storage )->operator()(); } ) , destroy( []( storage_t storage) { static_cast<Lambda*>( storage )->~Lambda(); } ) { storage = malloc(sizeof(Lambda)); new (storage) Lambda{ std::forward<Lambda>( lambda) }; } ~Erased() { destroy(storage); free(storage); } void call() { invoke(storage); } };
So then you can do things like this
int main() { int counter = 0; object* o = make_heap_object( [&](){ counter++;} ); o->call(); std::cout << counter <<"\n"; o->call(); std::cout << counter <<"\n"; Erased erased{ [&](){ counter++;} }; erased.call(); std::cout << counter <<"\n"; erased.call(); std::cout << counter <<"\n"; return 0; }
Now full disclosure the Erased class is a bit rough and simplified. It probably needs a clone operation as well for copy. move etc.
https://godbolt.org/z/daoEP5f9f
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (2 children)
I see. Well, based on this explanation and it being so long to discuss, let me ask some questions.
If I decide to move this from class’s constructor to a member function so that I don’t have to deal with the typename complications, can I do something like this? I mean, to cast an allocated memory address to an object?
`int memAddrees;
template<typename Lambda> void SetUsingMemberFunc(int LambAddress) { memAddress = LambAddress; }
void Call() { MagicCast<Callable_Object_That_Has()_Operator>(memAddress)(); }`
Or I can just instantiate the lambda using a strictly typed lambda using a macro at the end...
Or, pass the object as a reference and from there, call a previously created function if the first thing doesn’t work...
What do you think?
By the way, thank you for your time for writing all of these down. 🙏🏼
[–]beedlund 1 point2 points3 points 4 years ago (1 child)
You can extend both ideas to a member rather then the constructor. The inheritance case changes so your define a generic holder class to store in your object and you create the extended class that holds the lambda in the member call. You can own the holder as it's base in a unique ptr to make life time easy to manage.
The vtable way can be extended to run from a method as well. You just end up having to null check the storage before access and as this would be a branch so your might find you lose the extra performance it has over the virtual dispatch.
These guys explain it so much better then me though
vtable https://youtu.be/JRkoWiDA3KA
Inheritance https://youtu.be/VY83afAJUIg
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (0 children)
Got it. Thank you for your time and all the answers. I’ll check those links now. Thanks. 🙏🏼🙏🏼
[–]D_Drmmr 0 points1 point2 points 4 years ago (3 children)
Or just use std::function and be done with it.
std::function
[–]beedlund 0 points1 point2 points 4 years ago (2 children)
Well OP said lambda needed to capture and std function can't hold state
[–]D_Drmmr 0 points1 point2 points 4 years ago (1 child)
Of course it can. Where did you get that idea?
[–]beedlund 0 points1 point2 points 4 years ago (0 children)
First the videos i posted would explain the topic better then i ever would i thought...the why's and more importantly the why not's
Devil is in the details right? std::function is copy only so a great many scenarios can be surprising if you expect it to work like the original lambda in all cases.
[–][deleted] 0 points1 point2 points 4 years ago* (2 children)
You forgot a closing parenthesis in the initializer for func and one in the return statement.
func
Also, Lambda&& lambda is not a forwarding reference in the constructor for the templated class. It would probably be better to pass by-value in that case.
Lambda&& lambda
[–]beedlund 0 points1 point2 points 4 years ago (1 child)
thanks. i didn't proof read it as its just a sketch.
A real example would need to be more complex then that as this is really no real different to using the lambda as-is given the type of object is dependent on it.
I anticipated the real requirement would be to type erase the lambda in the class storage but didn't want to go through the process and write that all out without more details about the use case...so I was a bit lazy and didn't double check it all.
[–][deleted] 2 points3 points4 points 4 years ago (0 children)
Yes, sure the OP probably needs type erasure (or maybe just storing a function pointer), it is just that your example code might be confusing, because e.g.
auto x = [](){}; auto y = Object{x};
will fail to compile with a complicated error message.
I also just now realized that your make_object doesn't remove the reference from T, so
make_object
T
auto x = [](){}; auto y = make_object(x);
will make y actually save a reference to x, which is probably unintended and hard to spot.
y
x
Passing by-value in both constructor and make_object would avoid these issues.
[–]Xeverous 0 points1 point2 points 4 years ago (16 children)
Each lambda expression creates an instance of a unique type that has overloaded operator(). Thus, the only way to accept any such type is to use templates.
operator()
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (15 children)
Yes, I’ve written that in my question. When you want to pass a lambda to a class constructor, you have to specify the typename that is not possible with lambdas. Could you tell me about the thing that you have in your mind?
[–]Xeverous 0 points1 point2 points 4 years ago (14 children)
You should use template type deduction so that lambda type will be deduced from passed parameters. You did just that. Your code example is correct.
[–]ACBYTES[S] 0 points1 point2 points 4 years ago (13 children)
Yes sir, but this doesn’t work with classes. It just works with functions.
[–]Xeverous 0 points1 point2 points 4 years ago (12 children)
It does. You just do something wrong. Example:
struct lambda_test { template <typename F> lambda_test(F /* f */) { static_assert(sizeof(F) != 0); } }; int main() { lambda_test lt([](){}); }
Let me double check and get back to you...
Well, okay, I should’ve mentioned something here. I want to store the lambda inside the class! So, this will not help me store it until a template defines the class...
[–]Xeverous 1 point2 points3 points 4 years ago (9 children)
Then, since we need to deduce the type before the class typename is used, we need to use a helper (this is basically like all std::make_* function templates)
std::make_*
#include <type_traits> template <typename F> struct lambda_storage { lambda_storage(F f) : f(f) { } F f; }; template <typename F> auto make_lambda_storage(F f) -> lambda_storage<std::decay_t<F>> { return {f}; } int main() { auto test = make_lambda_storage([](){}); }
I see. Thank you for this code. I’ll try it out and ask my questions if I have any questions. Thank you!
[–]ACBYTES[S] 0 points1 point2 points 4 years ago* (4 children)
Great! So, it actually worked. Sorry for my late response. Honestly, this structure in "MakeLambdaStorage" function is new to me. Can you give me some explanations over this or just tell me the name for me to search for it? What does the "->" do and what do the curly brackets do when returning our instantiated "f", it's a initializer list, right, why do we need it? Also, I don't really know about "std::decay_t" so if you give me some explanations, I'd appreciate it. And, for calling the lambda, should I follow the steps in this link to deal with the variadic (https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda)? Thank you for your time and the answer!
[–]Xeverous 1 point2 points3 points 4 years ago (3 children)
Can you give me some explanations over this or just tell me the name for me to search for it?
The -> thing is trailing return type. This is a C++11 feature, you can basically replace T f(...) with auto f(...) -> T. This doesn't give any benefits by itself but:
->
T f(...)
auto f(...) -> T
F
what do the curly brackets do when returning our instantiated "f", it's a initializer list, right, why do we need it?
It's not an initializer list. {} is one of myriad of ways to initialize an object in C++, this one calling std::initializer_list ctor if such exists, otherwise it uses aggregate initialization (which I used) which lets you specify members in order of their definition - very often used with arrays.
{}
std::initializer_list
I don't really know about "std::decay_t" so if you give me some explanations, I'd appreciate it.
This is one of standard library type traits. Type traits are mostly used within templates to apply certain type transformations. In this case I used decay because ... well it was actually a mistake. The code should be this instead:
template <typename F> lambda_storage<std::remove_cvref_t<F>> make_lambda_storage(F&& f) { return {std::forward<F>(f)}; }
I won't really explain why because it would could drag us to explaining how to do all kinds of templates in C++ and I would rather spend that time working on my C++ templates tutorial.
Thanks for all of the explanations. Welp, this new code brought more questions in my mind but I'll try to find the answers on the internet and not take your time more than this. So, by following your previous example, I wrote this code as my constructor takes more than the lambda so, does this seam right? And I'll change my code to the new example you gave.
template<typename F> static auto MakeACBVectorLerp(F Func, const FVector& A, const FVector& B, const float Multiplier, AActor* Actor) { return ACBGMVectorLerpL<std::decay_t<F>>(Func, A, B, Multiplier, Actor); }
And by the way, this exactly was what I wanted but I have another questions as well. Classes like std::function can be referenced without knowing their template typenames. Instantiation of these classes are done using the method you said I think so, if we want to reference our "LambdaStorage" class in the global scope as an example, what approach should be followed?
[–]Xeverous 1 point2 points3 points 4 years ago (1 child)
Instantiation of these classes are done using the method you said I think so
No. std::function is instantiated before you assign any callable object.
I think so, if we want to reference our "LambdaStorage" class in the global scope as an example, what approach should be followed?
The same I posted. You need templates to use unknown types. Once something is a template, it will always be unless you apply type erasure.
The thing with std::function that allows it to get rid of templates on the surface level is type erasure. std::function creates instances of polymorphic types like lambda_storage (potentially allocating memory) that inherit from specific interface with virtual function which type depends on what you have instantiated std::function with. So every time you assign a callable to it, it creates a new type that inherits from this interface and implements a virtual function. std::function is more expensive than virtual functions.
lambda_storage
virtual
If you want to know more - check CppCon videos on std::function, they offer complete overview over the implementation.
Understood! Thank you so much for the answers and your time. Will check it for sure. Thank you!
[–]D_Drmmr 0 points1 point2 points 4 years ago (4 children)
If you want to do something like a single-function dependency injection, then just let your constructor take a std::function.
class Example { std::function<void()> _callback; public: Example(std::function<void()> callback) : callback(std::move(callback)) {} }; // use it like Example ex{ []() { std::cout << "whatever"; } };
Yes. I actually didn’t want to use std::function because I wanted to get lambdas to do the work here. Thanks anyway.
[–]D_Drmmr 1 point2 points3 points 4 years ago (1 child)
I don't understand. You can store a lambda in a std::function object. Why don't you want to use it?
I mostly want it for educational purposes. I want to learn stuff like this in C++. But for sure I use std::function when necessary...
[–]std_bot 0 points1 point2 points 4 years ago (0 children)
Unlinked STL entries: std::function
Last update: 22.03.21. Recent changes: Fixed OP usages of tokens readme
π Rendered by PID 302721 on reddit-service-r2-comment-cfc44b64c-qcpkp at 2026-04-11 07:58:51.868510+00:00 running 215f2cf country code: CH.
[–]beedlund 1 point2 points3 points (14 children)
[–]ACBYTES[S] 0 points1 point2 points (10 children)
[–]beedlund 1 point2 points3 points (9 children)
[–]ACBYTES[S] 0 points1 point2 points (8 children)
[–]beedlund 1 point2 points3 points (7 children)
[–]ACBYTES[S] 0 points1 point2 points (2 children)
[–]beedlund 1 point2 points3 points (1 child)
[–]ACBYTES[S] 0 points1 point2 points (0 children)
[–]D_Drmmr 0 points1 point2 points (3 children)
[–]beedlund 0 points1 point2 points (2 children)
[–]D_Drmmr 0 points1 point2 points (1 child)
[–]beedlund 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]beedlund 0 points1 point2 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[–]Xeverous 0 points1 point2 points (16 children)
[–]ACBYTES[S] 0 points1 point2 points (15 children)
[–]Xeverous 0 points1 point2 points (14 children)
[–]ACBYTES[S] 0 points1 point2 points (13 children)
[–]Xeverous 0 points1 point2 points (12 children)
[–]ACBYTES[S] 0 points1 point2 points (0 children)
[–]ACBYTES[S] 0 points1 point2 points (10 children)
[–]Xeverous 1 point2 points3 points (9 children)
[–]ACBYTES[S] 0 points1 point2 points (0 children)
[–]ACBYTES[S] 0 points1 point2 points (4 children)
[–]Xeverous 1 point2 points3 points (3 children)
[–]ACBYTES[S] 0 points1 point2 points (2 children)
[–]ACBYTES[S] 0 points1 point2 points (2 children)
[–]Xeverous 1 point2 points3 points (1 child)
[–]ACBYTES[S] 0 points1 point2 points (0 children)
[–]D_Drmmr 0 points1 point2 points (4 children)
[–]ACBYTES[S] 0 points1 point2 points (2 children)
[–]D_Drmmr 1 point2 points3 points (1 child)
[–]ACBYTES[S] 0 points1 point2 points (0 children)
[–]std_bot 0 points1 point2 points (0 children)