问题 隐式转换如何适用于非类型模板参数?


我猜(某些)隐式转换在传递非类型模板参数时适用。例如,应该有转换 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上, truefalse,和 false 印刷,这对我来说真的很奇怪。

在海湾合作委员会 truetrue,和 false 印刷,这是我所期待的。

在clang上,由于语句,代码根本不编译 f<4>();

候选模板被忽略:第一个模板参数的显式指定参数无效

那么,标准对此有何看法?非类型模板参数的隐式转换规则是什么?


9403
2018-01-28 04:55


起源

VC行为至少是明确的:它采用输入积分类型的LSB并将其用作布尔值。我仍然不知道哪种行为是正确的。 - Mark B
@MarkB不是, f<3>();仍然打印 false。 - Lingxi


答案:


从标准(§14.3.2/ 5):

对用作非类型的每个表达式执行以下转换 模板参数。如果一个   非类型 模板参数 无法转换为相应的类型 模板参数 然后   该计划格式不正确。

  • 对于非类型 模板参数 对于整数或枚举类型,应用转换常量表达式(5.19)中允许的转换。

在§5.19中,我们学习(强调我的):

一个 积分常数表达式 是隐式转换的整数或无范围枚举类型的表达式   到prvalue,其中转换的表达式是核心常量表达式。 ... 一个 转换常量表达式 的   类型 T 是一个表达式,隐式转换为类型为T的prvalue,其中转换后的表达式是一个核心   常量表达式和隐式转换序列仅包含用户定义的转换,lvalue-to-rvalue   转化(4.1),整体促销(4.5)和整体转化(4.7) 除了缩小转换率   (8.5.4)[ 注意: 这些表达式可以用在新表达式(5.3.4)中,作为案例表达式(6.4.2),   如果基础类型是固定的(7.2),数组边界(8.3.4),以及整数或   枚举非类型模板参数(14.3)。 - 尾注]

如此缩小转换(如转换 4 至 bool明确禁止使用整数常量表达式,在这种情况下,它必须作为非类型模板参数。这就是电话 f<4>() 病态的。

我相信Clang在发出错误时是正确的,而GCC和VC都不符合未发布任何诊断的要求。

[更新]这是 GCC Bug#57891,看起来它目前尚未分配。


14
2018-01-28 05:05



您能否提供有关转换标准的任何参考 0 和 1 至 bool 不缩小? - Lingxi
好吧,我似乎自己也找到了。 缩小转换是从整数类型或无范围枚举类型到不能表示原始类型的所有值的整数类型的隐式转换,除非源是常量表达式并且转换后的实际值将适合目标类型并在转换回原始类型时生成原始值。 - Lingxi
我已经为VC ++提交了一个错误 这里。 - ildjarn