This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
[Accepted as a DR at the July, 2019 meeting.]
A lambda expression in two translation units has distinct closuretypes, because each such expression's type is unique within the program.This results in an issue with the ODR, which requires that the definitionsof an entity are identical. For example, if
template <int> void f() {std::function<void()> f = []{};}
appears in two translation units, different specializations offunction's constructor template are called, which violates6.3 [basic.def.odr] bullet 6.4.
Issue 765 dealt with a similar problemfor inline functions, but the issue still remains for templates.
Proposed resolution, April, 2019:
Change 6.3 [basic.def.odr] paragraph 12 as follows:
...Given such an entity namedD defined in morethan one translation unit, then
each definition ofD shall consist ofthe same sequence of tokens, for which the definitionof a closure type is considered to consist of the sequenceof tokens of the correspondinglambda-expression;and
in each definition ofD, correspondingnames, looked up according to 6.5 [basic.lookup],
shall refer to an entity defined within the definitionofD, orshall refer to the same entity,after overload resolution (12.2 [over.match]) andafter matching of partial template specialization(13.10.4 [temp.over]), except that a name can referto
a non-volatile const object with internal or nolinkage if the object
has the same literal type in all definitionsofD,
is initialized with a constant expression(7.7 [expr.const]),
is not odr-used in any definition ofD, and
has the same value in all definitions ofD,
or
a reference with internal or no linkage initializedwith a constant expression such that the reference refers tothe same entity in all definitions ofD;
and
in each definition ofD, except withinthe default arguments and default template arguments ofD, correspondinglambda-expressions shallhave the same closure type (see below), and
in each definition ofD, correspondingentities shall have the same language linkage; and
in each definition ofD, the overloadedoperators referred to, the implicit calls to conversionfunctions, constructors, operator new functions and operatordelete functions, shall refer to the same function
, or to afunction defined within the definition ofD;andin each definition ofD, a default argument used by an(implicit or explicit) function callor a defaulttemplate argument used by an (implicit or explicit)template-id orsimple-template-id istreated as if its token sequence were present in thedefinition ofD; that is, the defaultargumentor default template argument is subjectto the requirements described in this paragraph (
and,if the default argument has subexpressions with defaultarguments, this requirement appliesrecursively)[Footnote: 9.3.4.7 [dcl.fct.default]describes how default argument names are looked up.—end footnote]; and...
IfD is a template and is defined in more thanone translation unit, then the preceding requirements shallapply both to names from the template's enclosing scope usedin the template definition (_N4868_.13.8.4 [temp.nondep]),and also to dependent names at the point of instantiation(13.8.3 [temp.dep]).
If the definitionsofD satisfy all these requirements, then thebehavior is as if there were a single definitionofD.These requirements also apply tocorresponding entities defined within each definition ofD (including the closure typesoflambda-expressions, but excluding entities definedwithin default arguments or defualt template arguments ofeitherD or an entity not defined withinD). For each such entity and forD itself,the behavior is as if there is a single entity with a singledefinition, including in the application of theserequirements to other entities. [Note: Theentity is still declared in multiple translation units, and6.6 [basic.link] still applies to thesedeclarations. In particular,lambda-expressions(7.5.6 [expr.prim.lambda]) appearing in the typeofD may result in the different declarationshaving distinct types, andlambda-expressionsappearng in a default argument ofD may stilldenote different types in different translationunits. —end note] If the definitionsofD do not satisfy these requirements, then thebehavior is undefined.program is ill-formed, no diagnostic required.[Example:inline void f(bool cond, void (*p)()) { if (cond) f(false, []{}); } inline void g(bool cond, void (*p)() = []{}) { if (cond) g(false); } struct X { void h(bool cond, void (*p)() = []{}) { if (cond) h(false); } };If the definition off appears in multipletranslation units, the behavior of the program is as if thereis only one definition off. If the definition ofg appears in multiple translation units, the programis ill-formed (no diagnostic required) because each suchdefinition uses a default argument that refers to a distinctlambda-expression closure type. The definition ofXcan sppear in multiple translation units of a valid program; thelambda-expressions defined within the default argumeht ofX::h within the definition ofX denote thesame closure type in each translation unit. —endexample]