C++模板实参推导:括号是否会构成非推导上下文?
问题结论
给非类型模板参数i添加单纯的括号不会使其成为非推导上下文,Clang在此处的行为不符合C++标准,属于编译器实现bug。
规则依据
[temp.deduct.type#17] 规定:如果在带有非类型模板形参的函数模板声明中,非类型模板形参在函数形参列表的某个子表达式中被使用,则该表达式属于前文规定的非推导上下文。
该条款的设计本意是限制编译器对包含运算的非类型模板参数进行推导:比如当非类型参数出现在i + 1这类运算表达式中时,编译器无法从给定的模板实参42反向求解出i的取值,因此将这类场景归为非推导上下文。
示例分析
第一种声明(所有编译器都拒绝)
template<int> struct S {}; template<int i> void f(S<i + 1>) {}
调用f(S<42>{})时,i是加法表达式i + 1的子表达式,符合非推导上下文的判定条件,因此所有编译器都会拒绝该调用,符合标准要求。
第二种声明(仅Clang错误拒绝)
template<int i> void f(S<(i)>) {}
C++标准明确规定,括号表达式的语义和被包裹的表达式完全等价,(i)和i没有任何差别,不属于需要反向求解的运算类表达式,因此S<(i)>完全可以正常推导i的取值。目前GCC、MSVC都能正确接受该调用,只有Clang存在实现缺陷,错误地将括号包裹的场景也判定为非推导上下文。
内容的提问来源于stack exchange,提问作者cigien
相关产品推荐
相关产品推荐

