在多个翻译单元中重复声明带闭包类型默认模板参数的模板是否违反ODR?
C++20允许在未求值上下文中使用lambda,因此可以编写如下代码:
template <class = decltype([]{})> class MyType {};
如果将这个类模板的定义包含在多个翻译单元(TU)中,是否会违反One Definition Rule (ODR)?
我查阅了N4860的§6.3(13.13)条款:
在每个此类定义中,……隐式或显式template-id或simple-template-id所使用的默认模板参数,视为其标记序列出现在D的定义中;即默认实参或默认模板参数需递归满足本款所述要求。
我原本的理解是,decltype([]{})属于声明类型,相关论文(§4)明确将此类情况标记为无效,这个理解是否正确?
编辑1
同一条款中的另一段内容让我感到困惑:
程序中可存在多个……
(13.4) — 模板实体(13.1),
……
(13.6) — 默认模板参数
的定义,前提是每个定义位于不同翻译单元且满足以下要求。对于在多个翻译单元中定义的此类实体D,所有D的定义需满足……
(13.10) — 在每个此类定义中,除D的默认实参和默认模板参数外,对应的lambda表达式应具有相同的闭包类型(见下文)。
针对上述代码,可以从两种角度应用该条款:
- a) 将D视为类模板(模板实体):此时(13.10)似乎表明默认模板参数可豁免lambda闭包类型一致的规则;
- b) 将D视为默认模板参数:此时需要遵守lambda闭包类型一致的规则。
条款末尾的“见下文”指向第14点:
若D是模板且在多个翻译单元中定义,则前述要求既适用于模板定义中使用的模板封闭作用域名称(13.8.3),也适用于实例化点的依赖名称(13.8.2)。这些要求同样适用于每个D定义中对应的实体(包括lambda表达式的闭包类型,但不包括D或非D内定义实体的默认实参或默认模板参数内定义的实体)。对于每个此类实体及D本身,其行为如同存在单个实体和单个定义,包括将这些要求应用于其他实体。[注:该实体仍在多个翻译单元中声明,6.6仍适用于这些声明。特别地,出现在D类型中的lambda表达式(7.5.5)可能导致不同声明具有不同类型,而出现在D默认实参中的lambda表达式在不同翻译单元中仍可能表示不同类型。——结束注]
我据此理解:若D为模板类,默认模板参数可豁免规则,但末尾注释指出,不同TU中默认模板参数内的lambda表达式闭包类型可能不同,这或许会违反ODR。
编辑2
我查阅了两个相关问题,但仍未得出最终结论:
- “关于多重定义项的注释含义”
- “出现在同一实体不同定义中的lambda表达式是否会产生相同的闭包类型?”
内容的提问来源于stack exchange,提问作者Andrea Agostini

