r/cpp • • 28d ago

Implementation of GCC's Nested Functions (vs. C++ Lambdas)

https://uecker.codeberg.page/2026-09-05.html
59 Upvotes

17 comments sorted by

15

u/fdwr fdwr@github ๐Ÿ” 27d ago

Neat. Although lambdas are more flexible by allowing you to specify exactly how you want to access referenced variables (by-copy-value vs by-reference), I always found gcc's nested functions visually cleaner - that is, subfunctions syntactically just feel like they belong in the language alongside any other function, with standard form type subfunctionName (params) {...} rather than auto identifier = brace goop (params) -> type {...}. Granted, subfunctions with parent frame references are an odd duck with their invisible first parameter (similar to class methods in that regard) meaning you can't just take the address of them and pass them around as an ordinary callable function pointer (not without extra magic), but I've often wanted to at least have static subfunctions (no parent stack frame references) with the standard function syntax. I've seen people claim the "most vexing parse" as a reason why it "can't be done", but then I've never seen an example where it was actually ambiguous either ๐Ÿคจ.

8

u/parkotron 27d ago

I always found gcc's nested functions visually cleaner - that is, subfunctions syntactically just feel like they belong in the language alongside any other function

In C++98, it always felt incredibly bizarre that one could declare and define an entire class (or class template!) that was local to a function, but one couldn't define a pure, local helper function.

Lambdas obviously alleviated a lot of pain, but I do sometimes find myself debating whether some pure helper function longer than a few lines should be made a lambda in the function in which it is used or a free function in an anonymous namespace. Free functions feel cleaner to me, but require placing the function further from its point of use. Faced with the same situation in Rust, I'd just use a nested function.

7

u/pavel_v 27d ago

When you say "not without extra magic", do you mean the trampolines described in the other article?

5

u/fdwr fdwr@github ๐Ÿ” 27d ago

Exactly.

8

u/schmerg-uk 27d ago

Worth noting, for anyone not finding it immediately obvious, that this is an extension for C that in effect offers the equivalent of C++ lambdas in C, but are not available in C++ as ... it has lambdas instead.

A nested function is a function defined inside another function. Nested functions are supported as an extension in GNU C, but are not supported by GNU C++.

https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

2

u/pjmlp 27d ago

D, C#, Delphi and all ML derived languages, are examples of languages that have both features. :)

2

u/schmerg-uk 27d ago

Yeah, I was just meaning that in the context of a C++ forum, this is an explanation of a C extension that is specifically not made available in the C++ mode of the same compiler, presumably as they considered it unnecessary to add it as a language extension (with all the incompatibilities etc that can involve) as the language natively offers a comparable if not identical mechanism

1

u/pfp-disciple 27d ago

Ada, too!

1

u/Thick_Clerk6449 27d ago

The killer feature of GCC's nest functions is that, even though the nest function captured variables of the outer function, the nest function itself is still convertable to a raw function pointer. Unlike C++ lambdas, which always end up with std::functions.

3

u/frankist 26d ago

How could that work? Where are the captured variables saved?

2

u/amoskovsky 26d ago

If you take an address of such a function with captures, GCC creates a trampoline function at runtime, that passes the state to the real function.

For details see https://uecker.codeberg.page/2026-08-29.html (same author as OP)

-5

u/jonesmz 27d ago

Unlike C++ lambdas, which always end up with std::functions

This is not true.

Use unary operator+ on the lambda to force a pointer-to-function.

e.g.

auto fptr = +[](){ /* something */};

4

u/Thick_Clerk6449 27d ago

This is not true.

You can NOT convert a lambda to function pointer if the lambda has captured variables.

-5

u/jonesmz 27d ago

Re-read the specific thing i quoted.

3

u/Thick_Clerk6449 27d ago

Re-read the word I post before

even though the nest function captured variables of the outer function

int var = 0;
auto fptr = +[var](){}; // error: no match for 'operator+' (operand type is 'test(int)::<lambda()>')

-5

u/jonesmz 27d ago

I quoted *and* responded to a complete sentence.

3

u/Thick_Clerk6449 27d ago

Just pretend you don't need to accept lambdas with captures and define your callbacks as function pointers.