按非类型参数类型的 C++ 模板特化

标签 c++ templates language-lawyer visual-c++-2017

相同模板函数的变体因非类型成员的类型不同是否有效?

template<typename T, unsigned int V>
void f(unsigned int& v) { v = V; }

template<typename T, bool B>
void f(bool& b) { b = B; }

目的是能够调用

unsigned int meaningOfLife;
f<sometype, 42>(meaningOfLife);

bool areYouAlive;
f<sometype, true>(areYouAlive);

clang 和 gcc 是沉默的,但 MSVC 报告

warning C4305: 'specialization': truncation from 'int' to 'bool'

我想避免要求指定常量类型:

f<sometype, bool, true>

并希望确保常量值和目标值匹配。

---- 麦克韦----

#include <iostream>

template<unsigned int V>
void f(unsigned int& v) { v = V; }

template<bool B>
void f(bool& b) { b = B; }

int main()
{
    unsigned int u { 0 };
    bool b { false };

    f<42>(u);
    f<true>(b);

    std::cout << u << b;
}

Rextester 示例:http://rextester.com/VIGNP16100

Warning(s):
source_file.cpp(14): warning C4305: 'specialization': truncation from 'int' to 'bool'
/LIBPATH:C:\boost_1_60_0\stage\lib 
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
421

最佳答案

简短回答:代码正常,MSVC 发出虚假警告。

MSVC 和 g++ 在非类型模板参数匹配方面都有错误,但它们确实为您的特定示例选择了正确的。


长答案:可以使用非类型模板参数重载函数模板。

然而,template-argument 与模板声明的匹配并不像预期的那样工作(无论如何是我)。所有匹配的模板都进入重载决议。它在任何阶段都不喜欢“完全匹配”。

根据 C++17 [temp.arg.nontype/]2,converted constant expressions被允许。这意味着,例如:

  • 42火柴intunsigned int .
  • 42u火柴intunsigned int .
  • 1u火柴unsigned int , intbool .

请注意,转换后的常量表达式不能包含缩小转换,并且 intbool正在缩小,除非值是值的常量表达式 01 .所以42不匹配 bool . (引用:C++17 [expr.const]/4)。

如果我们有以下设置:

template<unsigned int V> void g() {}
template<bool B> void g() {}

那么正确的行为是:

  • g<42>()电话 g<unsigned int> .
  • g<1>()是模棱两可的。
  • g<1u>()是模棱两可的。

MSVC 2017 和 g++ 7,8 都错误地允许 g<42>匹配g<bool> , 并报告 g<42>作为暧昧。

MSVC 发出您在生成无效匹配时看到的警告; g++ 根本不提供任何诊断。如果我们删除 unsigned int重载然后 g++ 静默接受无效代码而不进行诊断。


在您的代码中有一个非常量左值引用参数:

template<unsigned int V>  void h(unsigned int&) {}
template<bool B>          void h(bool&) {}

这很重要,因为重载决策可以根据函数参数进行选择。对于电话:

unsigned int m;
h<1u>(m);

然后 h 的两个重载进入过载决议,但是然后 h<unsigned int>获胜是因为h<bool>(m)将无效。

如上所述,调用 h<42>(m);在第一阶段获胜,因为这无法匹配 h<bool> ;但在 MSVC++(和 g++)中它错误地允许 h<bool>在这个阶段通过,但稍后会修剪它作为 h<1u>案件。

关于按非类型参数类型的 C++ 模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50499787/

相关文章:

c++ - 处理来自子类的 Windows 消息

c++ - 专门化类模板构造函数

python - Django 处理可选的 url 参数

c++ - 如果 Outer 类是我的 friend ,那么 Outer::Inner 类也是吗?

c - 序列点 "immediately before a library function returns"的结果是什么?

c++ - 基于 UDP 的 Asteroids 游戏待办事项 list

c++ - C++中两个线程的互斥量

c++ - 具有未定义行为但从未实际执行过的表达式是否会使程序出错?

c++ - 为什么重载运算符时会出现编译错误而不是替换失败?

c++ - 不同翻译单元内联函数的不同实现