24

I was experimenting with lambdas and compilers because of another question here on SO.
I've just realized (and it's perfectly normal indeed) that the following code is valid:

int main() {
    auto l = [](){};
    l.operator()();
}

Actually the standard says that the closure type has a public inline function call operator and so on, thus it makes sense to be able to invoke it.

What I can't explain by looking at the standard (well, the working draft) is the fact that GCC (6.1) compiles the following snippet (clang 3.9 does not):

int main() {
    auto l = []<typename>(){};
    l.operator()<void>();
}

No warnings, no errors. Is it valid code or should it be rejected by the compiler?

Community
  • 1
  • 1
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • [Compiled successfully](http://cpp.sh/4asuj) – amanuel2 Oct 09 '16 at 21:11
  • 1
    @amanuel2 I know that it compiles (with GCC at least), but the question is if it's valid or not. – skypjack Oct 09 '16 at 21:13
  • 1
    C++14 will allow "templated" lambdas, but that's with the `auto` keyword instead of the `<>` template syntax (see https://stackoverflow.com/questions/3575901/can-lambda-functions-be-templated). Maybe the GCC developers wanted to experiment with different ways to add this kind of functionality? – G. Sliepen Oct 09 '16 at 21:23
  • @G.Sliepen You are speaking about generic lambdas and I know them. Here I'm actually asking something that is slightly different. – skypjack Oct 09 '16 at 21:26
  • 3
    FWIW, I'm proposing to change this behavior in [P0428R0](https://github.com/ldionne/wg21/blob/master/generated/P0428R0.pdf). This will be part of the pre-Issaquah mailing. – Louis Dionne Oct 09 '16 at 22:49
  • @LouisDionne Interesting indeed. To be honest, the syntax is somehow ugly, but I see your reasons in the document. – skypjack Oct 10 '16 at 06:04
  • 1
    @LouisDionne: You mention in your paper that this extension was implemented in GCC in 2009, could this explain why GCC accepts this code even though it is not standard and thus be worthy of an answer? – Matthieu M. Oct 10 '16 at 07:30
  • @G.Sliepen "C++14 will" - you mean _has_, for 2 years. – underscore_d Oct 10 '16 at 09:34

3 Answers3

21

In N4140 5.1.2 [expr.prim.lambda], a Lambda expression is defined as

lambda-introducer lambda-declaratoropt compound-statement

where a "lambda-introducer" is the [], enclosing an optional "lambda-capture" and "lambda-declaratoropt" is the stuff starting with "( parameter-declaration-clause )".

[]<typename>(){}

does not meet that requirement because there is something between the lambda introducer and the lambda declarator, so it is not a valid lambda expression.

Thus, your example code is not valid C++ and should be rejected by the compiler.


As this is also tagged , I clicked through the list of GNU C++ extensions. I did not find any extension that would make the syntax in question legal in GNU C++.

However, according to Section 4 of this proposal (P0428R0), which proposes to add templated lambdas to C++, gcc got an experimental implementation of the aforementioned paper in 2009. This probably explains why gcc doesn't complain here.

L. F.
  • 19,445
  • 8
  • 48
  • 82
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
2

It seems to be a GCC extension (templated lambdas).

#include <iostream>

int main() {
    auto l = []<typename T>(T const& x){ std::cout << __PRETTY_FUNCTION__ << " " << x << std::endl;};
    l(42);
    l("Hello world");
}

results in

main()::<lambda(const T&)> [with T = int] 42
main()::<lambda(const T&)> [with T = char [12]] Hello world
etarion
  • 16,935
  • 4
  • 43
  • 66
  • Can you provide a link to the documentation of this? I've not been able to find it and that's why I excluded the possibility of being an extension. Thank you. – skypjack Oct 10 '16 at 13:01
  • http://gcc.gnu.org/ml/gcc/2009-08/msg00174.html is the closest I could find @skypjack – etarion Oct 11 '16 at 05:43
0

The given code is well-formed and works as intended since C++20.

Per [expr.prim.lambda]:

lambda-expression:
    lambda-introducer lambda-declaratoropt compound-statement
    lambda-introducer < template-parameter-list > requires-clauseopt lambda-declaratoropt compound-statement

The last line reflects this syntax. Per [expr.prim.lambda]/5:

A lambda is a generic lambda if there is a decl-specifier that is a placeholder-type-specifier in the decl-specifier-seq of a parameter-declaration of the lambda-expression, or if the lambda has a template-parameter-list.

L. F.
  • 19,445
  • 8
  • 48
  • 82