Lambda函数调用运算符何时被实例化?
非泛型Lambda在模板实体中的实例化争议
先看这段代码:
template <class T, auto F = [](T x) { *x; }> void foo(T t) {} void foo(...) {} int main() { foo(42); }
相关C++标准条款如下:
[expr.prim.lambda.closure]/2:闭包类型在包含对应lambda表达式的最小块作用域、类作用域或命名空间作用域中声明。[...]
当对foo<int>进行模板替换时,会在全局作用域中声明一个lambda闭包类型,它的函数调用运算符并非模板。这个闭包类型属于模板实体([temp.pre]/8.5),因此其函数调用运算符也属于模板实体([temp.pre]/8.3)。但根据[temp.inst]/5的规定,只有函数模板特化或者类模板特化的成员才会被隐式实例化,而这个调用运算符不属于这两类。
对这段代码的解读有两种:
- 最直接的解读:lambda的函数调用运算符不会按需实例化,而是和闭包类型一同定义。GCC的行为就符合这种解读——它会拒绝这段代码,因为
*x在x是int时非法。 - 另一种解读:标准措辞存在疏漏,该调用运算符本该像函数模板特化那样按需实例化。如果是这样,这段代码就是合法的,会调用
foo<int>。
而Clang的行为和这两种解读都不符:它调用了foo(...),仿佛foo<int>在模板替换的直接语境中发生了失败,但实际上lambda表达式并不在直接语境中,所以这种行为是错误的。
内容的提问来源于stack exchange,提问作者Brian Bi
相关产品推荐
相关产品推荐

