How to immediately invoke a C++ lambda?
Solution 1
But now that has me thinking -- did I do this correctly?
Yes you did.
Is there a better way in C++11 or C++14 to tell the compiler that I want it to immediately invoke a lambda I've written?
Not that I know of. A lambda is also just a function object, so you need to have a ()
to call it, there is no way around it (except of course some function that invokes the lambda like std::invoke
).
If you want you can drop the ()
after the capture list, because your lambda doesn't take any parameters.
Or is appending an empty
()
like I did the usual way to do this?
Yes, it is the shortest way. As said before, std::invoke
would also work instead, but it requires more typing. I would say a direct call with ()
is the usual way it is done.
Solution 2
In C++17 you can use std::invoke
. This does the exact same thing as you did, but perhaps you will find this clearer.
#include <iostream>
#include <functional>
void foo(int i)
{
std::cout << i << '\n';
}
int main()
{
foo( std::invoke( []() { return 1; } ) );
}
Solution 3
There's no way to tell the compiler to invoke the lambda immediately. The simplest course (both in terms of complexity and number of typed characters) is what you did already. It's also very idiomatic for anyone who has worked with languages that have closures (I'm thinking JavaScript here).
If you want to avoid the syntax, then either modify SomeBase
or complexstuff
to execute the callable.
If all you want is syntactic sugar for invoking the lambda, you can always do what something like Alexandrescu's SCOPE_GUARD does, and abuse operator overloading:
#include <iostream>
namespace detail {
enum class invoke_t{};
template<class Callable>
auto operator+(invoke_t, Callable c) -> decltype(c()) {
return c();
}
}
constexpr detail::invoke_t invoke{};
int main() {
invoke + []() {
std::cout << "called";
};
}
But I wouldn't. Inventing your own DSL will just make your code worse to maintain. Stick to the idioms that utilize plain language constructs.
Solution 4
Is there a better way
You could also consider having a private static member function building the complexstuff
, something like
class MyFoo : public Base {
private:
static SomeComplexType compute_complex_stuff() {
SomeComplexType complexstuff;
/*compute the complexstuff */
return complexstuff;
};
public:
MyFoo() : Base(compute_complex_stuff()) {};
};
I don't know if it is better than defining a lambda expression and applying it immediately; that is IMHO a matter of taste; for a short lambda body I would prefer a lambda expression immediately applied (but perhaps some compiler would create the temporary closure in that case, so it might be slower without optimizations; I expect most C++11 compilers to be able to make that optimization).
BTW, GCC provides the statement expression language extension (also understood by Clang) for your purposes. With it you could write
MyFoo::MyFoo : Base (({
SomeComplexType complexstuff;
/*compute the complexstuff */
return complexstuff;
}) {};
Related videos on Youtube
Stéphane
Linux, Ubuntu, C++ developer. https://www.linkedin.com/in/scharette http://www.ccoderun.ca/
Updated on June 04, 2022Comments
-
Stéphane almost 2 years
A constructor from a class I'm inheriting requires a non-trivial object to be passed in. Similar to this:
MyFoo::MyFoo() : SomeBase( complexstuff ) { return; }
The
complexstuff
has little to do withMyFoo
, so I didn't want to have to pass it in.Instead of writing some kind of 1-off temporary function that returns
complexstuff
I used a lambda. What took me a few minutes to figure out is I have to invoke the lambda. So my code now looks like this:MyFoo::MyFoo() : SomeBase( []() { /* blah blah do stuff with complexstuff */ return complexstuff; } () ) { return; }
If you didn't catch it, it is subtle. But after the lambda body, I had to put
()
to tell the compiler to immediately "run" the lambda. Which made sense after I figured out what I had done wrong. Otherwise, without the()
to invoke the lambda, gcc says something similar to this:error: no matching function for call to 'SomeBase(<lambda()>)'
But now that has me thinking -- did I do this correctly? Is there a better way in C++11 or C++14 to tell the compiler that I want it to immediately invoke a lambda I've written? Or is appending an empty
()
like I did the usual way to do this?-
Basile Starynkevitch almost 7 years@n.m.: because the complexstuff needs some statements to be computed (such as some
for
loop) -
AnT stands with Russia almost 7 years@n.m.: Why not? This is basically the standard way to achieve what GCC's expression statements extension is offering (
({ ... })
). I.e. when you need an expression that involves more than just operators. -
n. m. almost 7 yearsSo this is for embedding statements in an expression. Did I understand it correctly ?
-
rwong about 6 yearsAs a matter of coding style, the // complexstuff // should be in a private static member function of the same class (MyFoo). In other words, "1-off temporary function" would have been the correct approach. You would have been "corrected" if your code were reviewed by other people. There is no reason to use lambda in this case. I leave this comment because apparently someone's answer (not mine) got downvoted (not me) for not pointing out this obvious issue. The question is legitimate but the code sample might have seemed superfluous to some StackOverflow users.
-
-
Potatoswatter almost 7 yearsJust to illustrate the middle point,
[](){}
is an empty lambda function object, and[]{}()
is avoid
expression resulting from evaluating an empty lambda. -
Justin almost 7 yearsInventing your own DSL will make your code worse to maintain for most purposes. But for some rare cases, it can make the code easier to maintain. For example, something like
fn("myFunctionName")(1, "hi", cast("void *")(variable("var")))
is a lot more readable thanFunction{ "myFunctionName", { FunctionArgument{ std::to_string(1) }, FunctionArgument{ "hi" }, FunctionArgument{ Cast{ "void *", Variable{ "var" } } } } }
(especially if it gets more complex). It just requires that the maintainer understands the dsl though -
StoryTeller - Unslander Monica almost 7 years@Justin - That's a lot of ifs :) I agree that a DSL isn't inherently a bad thing (SCOPE_GUARD, overloading operator| for ranges and so forth come to mind), but it's very much a judgement call.
-
ildjarn almost 7 yearsThis is 100% pointless.
std::invoke
is for generic code where you might be given a function object, PMF, function pointer, etc. When you already know how to invoke your callable,std::invoke
serves no purpose other than to slow build times. -
Henri Menke almost 7 years@ildjarn Thank you for repeating what I said in the answer and downvoting.
-
ildjarn almost 7 yearsIt doesn't "do the exact same thing", it does a lot more, hence the increased build times. You didn't mention that. ;-] This is an abuse of
std::invoke
more than a use of it; even if it's subjectively "clearer" in some context, it's objectively worse regardless when you have a fixed form of callable. -
alfC over 3 years@ildjarn
std::invoke
is used here to stress out the function invocation and not rely the()
-detail which can be missed by the person reading the code. This alone can save developer's time. The technique is explained in this book: bfilipek.com/2016/11/… -
Dietmar Kühl about 3 yearsI guess,
invoke
should be declaredinline
to allow definitions in multiple translation units:inline constexpr enum {} invoke{};
-
StoryTeller - Unslander Monica about 3 years@DietmarKühl - I was relying on the implied internal linkage of const namespace scoped objects. But now I see that probably made the template a big odr violation on account of the annonymous type of the object in every TU. It should be fixed now, and be valid C++11 (my original intent).