我猜(某些)隐式转换在传递非类型模板参数时适用。例如,对于int
等表达式,应该从std::size_t
转换为std::array<int, 7>
。但是,请考虑以下代码:
template <bool>
void f() {
std::cout << "false\n";
}
template <>
void f<true>() {
std::cout << "true\n";
}
int main() {
f<1>();
f<4>();
f<0>();
}
我希望int
在这里隐式转换为bool
。但VC,GCC和clang的行为不同。
在VC上,会打印true
,false
和false
,这对我来说真的很奇怪。
在GCC上,会打印true
,true
和false
,这正是我所期望的。
在clang上,由于语句f<4>();
,代码根本无法编译。
忽略候选模板:第一个模板参数
的显式指定参数无效
那么,标准对此有何看法?非类型模板参数的隐式转换规则是什么?
答案 0 :(得分:14)
从标准(§14.3.2/ 5):
对用作非类型模板参数的每个表达式执行以下转换。如果一个 非类型 template-argument 无法转换为相应 template-parameter 的类型 该计划格式不正确。
- 对于整数或枚举类型的非类型模板参数,将应用转换常量表达式(5.19)中允许的转换。
在§5.19中,我们学习(强调我的):
整数常量表达式是整数或无范围枚举类型的表达式,隐式转换 到prvalue,其中转换的表达式是核心常量表达式。 ...一个转换的常量表达式 type
T
是一个表达式,隐式转换为类型为T的prvalue,其中转换后的表达式是一个核心 常量表达式和隐式转换序列仅包含用户定义的转换,lvalue-to-rvalue 转化(4.1),整体促销(4.5)和整数转化(4.7)除了缩小转化次数 (8.5.4)即可。 [注意:这样的表达式可以用在新表达式(5.3.4)中,作为case表达式(6.4.2), 如果基础类型是固定的(7.2),作为数组边界(8.3.4),还是作为整数或者,则作为枚举器初始值设定项 枚举非类型模板参数(14.3)。 -end note]
因此,对于整数常量表达式,显式不允许缩小转换(如将4
转换为bool
),在这种情况下,这些表达式需要作为非类型模板参数。这使得电话f<4>()
形成不良。
我相信Clang在发出错误方面是正确的,GCC和VC都不符合未发布任何诊断的信息。
[更新]这是GCC Bug #57891,看起来好像是未分配的。