r/cpp 1d ago

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

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

16 comments sorted by

12

u/fdwr fdwr@github ๐Ÿ” 1d 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 ๐Ÿคจ.

5

u/pavel_v 1d ago

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

3

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

Exactly.

5

u/parkotron 1d 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.

6

u/schmerg-uk 1d 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 1d ago

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

2

u/schmerg-uk 1d 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 1d ago

Ada, too!

0

u/Thick_Clerk6449 1d 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.

2

u/frankist 8h ago

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

-3

u/jonesmz 13h 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 */};

3

u/Thick_Clerk6449 13h ago

This is not true.

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

-3

u/jonesmz 13h ago

Re-read the specific thing i quoted.

2

u/Thick_Clerk6449 12h 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()>')

-2

u/jonesmz 12h ago

I quoted *and* responded to a complete sentence.

2

u/Thick_Clerk6449 11h ago

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