P2285R1 - Are default function arguments in the immediate context? WG21
Posted by u/sfinae_or_die · 6 hr. ago

Authors: Andrzej Krzemiński, Tomasz Kamiński
Document: P2285R1
Date: 2026-02-23
Target: EWG
Link: wg21.link/p2285r1

Ever wonder why std::constructible_from<C<std::string>> gives you a different answer on every compiler? This paper looks at whether default function arguments and default member initializers should count as part of the "immediate context" for SFINAE and concept checking.

The problem: GCC says no, Clang hard-errors, MSVC says maybe, and the standard doesn't have a clear answer. The paper's strongest argument is that the standard library already works around this - unordered_set needs four separate constructor overloads instead of one with default arguments, because default args don't participate in substitution failure.

R1 adds implementation analysis (including a tricky lambda-in-default-argument case that has ABI implications) and expands scope to cover default member initializers. The recommendation is to put default arguments in the immediate context if vendors can make it work, with a fallback to at least mandating consistent behavior.

▲ 47 points (78% upvoted) · 8 comments
sorted by: best
u/just_a_process_nerd 23 points 2 hr. ago 🏆

For anyone following this: EWG polled on this at Croydon. The result was consensus that default function arguments are not in the immediate context.

The broader direction is moving toward P4149 - a paper that tries to properly define what "immediate context" means in the first place, rather than expanding it piecemeal. Krzemiński is a co-author on that one too, so this paper's analysis isn't wasted - it got folded into a larger effort.

The practical takeaway: the overload-explosion pattern for library constructors is here to stay. If you're writing a library and you want constructible_from to give the right answer, you still need separate overloads with requires clauses instead of default arguments.

u/constexpr_everything_42 18 points 5 hr. ago

The strongest argument in the paper is about the standard library:

If the Standard Library cannot consume the feature, this is a forecast that the users may also be unable to consume it.

Look at the unordered_set constructor signature explosion. Instead of a single constructor with defaulted parameters, the library has to provide separate overloads with progressively constrained requires clauses - all because default arguments don't participate in SFINAE. That's a real API design tax that trickles down to every library author who wants their constructors to play nice with constructible_from.

The question is whether fixing this is worth the implementation cost. The paper acknowledges the lambda-in-default-argument problem is non-trivial, and EDG says the default member initializer part might not be implementable at all. At some point you have to ask whether the workaround (more overloads) is cheaper than the fix.

u/sfinae_or_die 5 points 4 hr. ago

Yeah, the real world has already routed around this with the overload explosion pattern. The question is whether we're ok with that being the permanent answer.

u/former_clang_contributor 14 points 4 hr. ago

The lambda example from Richard Smith in section 4 is the real blocker. If default arguments are in the immediate context, a failed substitution instantiates a function-static variable as a side effect, and then a later successful substitution in the same TU has to deal with the consequences.

The known workaround - each use of the default argument gets a unique lambda type - has ABI implications. Name mangling has to encode where the default argument was used, not just where it was defined.

Clang and EDG sidestep this entirely by hard-erroring on substitution failure in default arguments. It's not the user-friendly answer, but it's the sound one. GCC does something different but I'm not convinced it handles the lambda case correctly either.

u/template_wizard_2020 9 points 3 hr. ago

The compiler divergence table is the best part of the paper. Four compilers, five different type traits, and the results are all over the place. MSVC outputs 1 for is_default_constructible but 0 for default_initializable on the same type.

The paper's description of MSVC's approach is pretty telling:

if the default function argument exists assume it will be valid

That's... optimistic. GCC at least consistently returns 0 for everything. Clang gives up and hard-errors on all of them. At minimum we need a consistent answer, even if it's "not in the immediate context." Compiler divergence on traits is worse than the wrong answer.

u/compile_time_is_my_runtime 11 points 5 hr. ago

Four compilers, four answers. I love this language.

u/daily_networking_complainer 3 points 1 hr. ago

Meanwhile I'm still waiting for networking to exist in the standard. But sure, let's spend another decade on whether default arguments are in the immediate context.

u/compile_time_is_my_runtime 2 points 47 min. ago

At this rate compile times will be faster than the committee process.