Lambda能否作为模板实参?Clang与GCC编译差异解析
嘿,这个问题其实涉及到C++标准中关于无捕获的lambda和模板非类型参数的细节,咱们一步步来拆解:
首先先看你给出的两段代码:
第一段代码,直接在模板参数里用+[]{}:
template<void(*)()> struct s{}; int main() { s<+[]{}> t; }
这段在Clang能正常编译,但GCC会抛出两个错误:
main.cpp:5:8: error: lambda-expression in template-argument
s<+[]{}> t; ^main.cpp:5:12: error: template argument 1 is invalid
s<+[]{}> t; ^
第二段代码先把转换后的结果存到constexpr变量里,就能在Clang和GCC中都顺利编译:
template<void(*)()> struct s{}; constexpr auto f = +[]{}; int main() { s<f> t; }
结论:Clang的处理是符合C++标准的,GCC早期版本存在实现缺陷
为什么这么说呢?咱们对照C++标准的规定来看:
- 无捕获的lambda可以隐式转换为对应的函数指针类型,而且这个转换操作在常量表达式语境下是有效的(C++17及以后支持constexpr lambda,无捕获lambda本身就属于constexpr范畴)。
- 模板非类型参数允许使用常量表达式,只要表达式的类型匹配模板参数的要求(这里就是
void(*)()类型的函数指针)。
所以+[]{}这个表达式,本质是把无捕获lambda转换为函数指针,而且这个转换结果是一个合法的常量表达式,完全满足模板非类型参数的要求。
GCC早期版本的问题在于,它没有正确处理“直接在模板参数位置进行lambda到函数指针的常量转换”这个场景,但当你把转换结果先赋值给一个constexpr变量时,它能识别这个变量是常量表达式,所以可以正常编译——这说明它其实认可这个转换结果是合法的,只是对直接在模板参数里的情况处理不到位。
好在后续的GCC版本(比如GCC 10及之后)已经修复了这个问题,现在也能正确编译第一段代码了。
内容的提问来源于stack exchange,提问作者Guillaume Racicot
相关产品推荐
相关产品推荐

