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.
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_fromto give the right answer, you still need separate overloads withrequiresclauses instead of default arguments.The strongest argument in the paper is about the standard library:
Look at the
unordered_setconstructor signature explosion. Instead of a single constructor with defaulted parameters, the library has to provide separate overloads with progressively constrainedrequiresclauses - 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 withconstructible_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.
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.
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.
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
1foris_default_constructiblebut0fordefault_initializableon the same type.The paper's description of MSVC's approach is pretty telling:
That's... optimistic. GCC at least consistently returns
0for 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.Four compilers, four answers. I love this language.
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.
At this rate compile times will be faster than the committee process.