31

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 with MyFoo, 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?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Stéphane
  • 19,459
  • 24
  • 95
  • 136
  • Why write a lambda and immediately invoke it? It doesn't make much sense. – n. m. could be an AI Jul 02 '17 at 07:28
  • 2
    @n.m.: because the complexstuff needs some statements to be computed (such as some `for` loop) – Basile Starynkevitch Jul 02 '17 at 07:29
  • 5
    @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. – AnT stands with Russia Jul 02 '17 at 07:31
  • 3
    So this is for embedding statements in an expression. Did I understand it correctly ? – n. m. could be an AI Jul 02 '17 at 07:34
  • 1
    As 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. – rwong Feb 28 '18 at 17:53
  • I shared some related ideas here: [What is a lambda expression in C++11?](https://stackoverflow.com/a/15153194/86967) – Brent Bradburn Apr 22 '18 at 00:15

4 Answers4

29

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.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • 11
    Just to illustrate the middle point, `[](){}` is an empty lambda function object, and `[]{}()` is a `void` expression resulting from evaluating an empty lambda. – Potatoswatter Jul 02 '17 at 07:34
10

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; } ) );
}
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • 4
    This 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. – ildjarn Jul 02 '17 at 08:38
  • @ildjarn Thank you for repeating what I said in the answer and downvoting. – Henri Menke Jul 02 '17 at 08:40
  • 6
    It 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. – ildjarn Jul 02 '17 at 08:40
  • 3
    @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: https://www.bfilipek.com/2016/11/iife-for-complex-initialization.html#improving-readability-of-iife – alfC Oct 17 '20 at 08:51
8

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:

Live example

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

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • That `operator+` is funny :P Never seen something like this. Can't you use `decltype(auto)` for the return type instead of the trailing return type? Aren't they the same? – Rakete1111 Jul 02 '17 at 08:02
  • 1
    Inventing 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 than `Function{ "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 – Justin Jul 02 '17 at 08:21
  • @Rakete1111 - The OP tagged C++11, I just stuck to that realm. You can use return type deduction, of course. – StoryTeller - Unslander Monica Jul 02 '17 at 08:28
  • @StoryTeller Well, in the question OP mentioned C++14 too, so I just added that tag to the question... :) – Rakete1111 Jul 02 '17 at 08:28
  • 1
    @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. – StoryTeller - Unslander Monica Jul 02 '17 at 08:31
  • I guess, `invoke` should be declared `inline` to allow definitions in multiple translation units: `inline constexpr enum {} invoke{};` – Dietmar Kühl Apr 08 '21 at 18:49
  • @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). – StoryTeller - Unslander Monica Apr 08 '21 at 19:07
2

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;
}) {};
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547