以下程序使用 gcc 4.8.1 编译没有错误或警告,
-Wall -std=c++11
:
template<unsigned N>
struct A{};
int main(){
A<1-2> a;
(void)a;
return 0;
}
具有相同选项的 clang 3.3 会出现此错误:
错误:非类型模板参数的计算结果为 -1,不能将其缩小为类型 'unsigned int' [-Wc++11-narrowing]
根据这个问题,看起来 gcc 的当前政策只是在标准指示错误和 clang 给出指示错误的地方对缩小转换发出警告。但在这种情况下 gcc 甚至没有给出警告。
标准在第 8.5.4/7 节(在那个问题中重现)给出的缩小转换错误的例子都没有涵盖非类型模板参数的缩小转换的情况,但在第 14.3.2/5 节标准说:
对于整数或枚举类型的非类型模板参数,应用转换后的常量表达式 (5.19) 中允许的转换。
§ 5.19/3 说:
T 类型的已转换常量表达式是一个字面常量表达式,隐式转换为 T 类型,其中在字面常量表达式中允许隐式转换(如果有),并且隐式转换序列仅包含用户定义的转换,左值到-右值转换 (4.1)、整数提升 (4.5) 和除窄转换(8.5.4) 之外的整数转换 (4.7)
(我的重点)。
在我看来,这似乎意味着即使按照自己的标准 gcc 在这种情况下根本没有诊断出缩小转换是错误的。我读对了吗?是否有基于标准的反驳?
我问这个问题的感觉不仅仅是好奇。在递归 TMP 设置中,clang 的错误诊断在这种情况下将查明一个错误,其中无符号的非类型模板参数低于 0,而您从 gcc 得到的只是“超出了最大模板实例化深度”。