【问题标题】:How implicit conversion works for non-type template parameters?非类型模板参数的隐式转换如何工作?
【发布时间】:2015-03-26 22:02:17
【问题描述】:

我猜(某些)隐式转换适用于传递非类型模板参数时。例如,对于像std::array<int, 7> 这样的表达式,应该有从intstd::size_t 的转换。但是,请考虑以下代码:

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 上,truefalsefalse 被打印出来,这对我来说真的很奇怪。

在 GCC 上,truetruefalse 被打印出来,这是我所期望的。

在 clang 中,由于声明 f&lt;4&gt;();,代码根本无法编译。

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

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

【问题讨论】:

  • VC 的行为至少很清楚:它采用输入整数类型的 LSB 并将其用作布尔值。我仍然不知道哪种行为是正确的。
  • @MarkB 不是真的,f&lt;3&gt;(); 仍然打印false

标签: c++ templates type-conversion implicit-conversion template-specialization


【解决方案1】:

来自标准(§14.3.2/5):

对用作非类型模板参数的每个表达式执行以下转换。如果一个 非类型 template-argument 无法转换为对应 template-parameter 的类型则 程序格式不正确。

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

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

整数常量表达式是整数或无范围枚举类型的表达式,隐式转换 到prvalue,其中转换后的表达式是核心常量表达式。 ... 转换后的常量表达式 T 类型是一个表达式,隐式转换为 T 类型的纯右值,其中转换后的表达式是一个核心 常量表达式和隐式转换序列仅包含用户定义的转换,左值到右值 转换 (4.1)、积分提升 (4.5) 和积分转换 (4.7) 除了缩小转换 (8.5.4)[ 注意: 此类表达式可用于新表达式 (5.3.4),如 case 表达式 (6.4.2), 如果底层类型是固定的(7.2),作为枚举器初始化器,作为数组边界(8.3.4),作为整数或 枚举非类型模板参数 (14.3)。 ——尾注]

因此,对于整型常量表达式,显式不允许缩小转换(如将4 转换为bool),在这种情况下,它需要作为非类型模板参数。这使得调用f&lt;4&gt;() 不正确。

我相信 Clang 发出错误是正确的,而 GCC 和 VC 都因未发出任何诊断而不符合标准。

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

【讨论】:

  • 您能否提供有关从01bool 的转换不会缩小的标准参考?
  • 好的,我好像自己找到了。 窄化转换是从整数类型或无作用域枚举类型到整数类型的隐式转换,它不能表示原始类型的所有值,除非源是常量表达式并且转换后的实际值适合目标类型,并在转换回原始类型时生成原始值。
  • 我已经为 VC++ here提交了一个错误。
猜你喜欢
  • 1970-01-01
  • 2016-01-23
  • 2016-03-01
  • 2019-11-10
  • 1970-01-01
  • 2021-09-02
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多