3

In the example in this cppreference page, there is this line of code

[](...){}(n3, n4, x, r2);

What's going on with the "(n3, n4, x, r2)"? Because in this cppreference page, it says all 8 forms of a lambda should end with { body }.

I tried searching online but no luck. Thanks in advance.

3

2 Answers 2

7

First, the lambda is:

[](...){}

This is a lambda that captures nothing, has an empty function block, the {}, and uses a C style variadic function parameter to accept any number of parameters.

The whole:

[](...){}(n3, n4, x, r2);

Is what is known as an "immediately invoked lambda expression", as you define the lambda and call it at the same time. The call is the (n3, n4, x, r2), where those 4 variables are passed to the lambda, and nothing happens since the lambda has an empty function block.


To see an actual use case, instead of having to write:

template<typename Tuple, typename Function, std::size_t... Is>
void tuple_for_each_impl(const Tuple& tup, Function func, std::index_sequence<Is...>)
{
    (func(std::get<Is>(tup)), ...);
}

template<typename... Ts, typename Function>
void tuple_for_each(const std::tuple<Ts...>& tup, Function func)
{
    tuple_for_each_impl(tup, func, std::make_index_sequence<sizeof...(Ts)>{});
}

to make a for_each for a tuple, you can instead use:

template<typename... Ts, typename Function>
void tuple_for_each(const std::tuple<Ts...>& tup, Function func)
{
    [&]<std::size_t... Is>(std::index_sequence<Is...>)
    {
        (func(std::get<Is>(tup)), ...);
    }(std::make_index_sequence<sizeof...(Ts)>{});
}
Sign up to request clarification or add additional context in comments.

6 Comments

Okay yeah, kind of embarrassed I didn't see what's going on -- the "(n3, n4, x, r2)" are the arguments to the lambda, which are received as the parameter "..." in the lambda. Thanks!
@Gymkata Exactly. I also updated this with a real world example on how it can help make code a little simpler, at least imo.
std::apply([&](const auto&... elems){ (func(elems), ...); }, tup); in C++17 (std::apply)
@Jarod42 Doh, I always forget about std::apply. at least the technique in general can be used for other things.
@Gymkata Copy-paste error. The code posted was adapted from other code I had and I forgot to remove that part.
|
5

The full line (code plus comment) provides a clue to what is going on.

[](...){}(n3, n4, x, r2); // see also: [[maybe_unused]]

It is not directly stated, but the comment provides an alternative way to get the same effect. That is, if the variables had been declared with [[maybe_unused]] then this line would not be needed. The purpose of this line is to use the otherwise-unused variables so that the surrounding example code can be compiled without warnings (cppreference.com strives for clean code examples).

That brings us to the question of how the variables are being used by this line. They are grouped by a pair of parentheses and separated by commas. If this came after (void), it would be a traditional cast-to-void of unused variables using the comma operator. However, it instead comes after [](...){}, which is a lambda expression (and which satisfies the question's mentioned criterion "end with { body }"). Since it comes after a functional, the parentheses indicate the function-call operator and contain an argument list.

Approaching the code from this angle, parsing right-to-left, we've avoided the question. The lambda is just [](...){} and what follows the lambda is an argument list. The lambda is immediately executed with no effect other than "using" the variables. While it does not use them much (the ... is a concise way to say "I'm intentionally ignoring the parameters"), it is enough to satisfy the "unused variable" warning of popular compilers. It's a nifty bit of syntax, as long as it does not end up confusing people.

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.