按非类型参数类型的 C++ 模板特化
C++ Template specialization by type of non-type parameter
相同模板函数的变体因非类型成员的类型不同是否有效?
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>
并希望确保常量值和目标值匹配。
---- mcve ----
#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++ 在非类型模板参数匹配方面都有错误,但它们 select 适合您的特定示例。
长答案:使用非类型模板参数重载函数模板是可以的。
然而,模板参数 与模板声明的匹配并不像预期的那样工作(无论如何是我)。所有匹配的模板都进入重载决议。它在任何阶段都不喜欢 "exact match".
根据 C++17 [temp.arg.nontype/]2,converted constant expressions 是允许的。这意味着,例如:
42
匹配 int
和 unsigned int
.
42u
匹配 int
和 unsigned int
.
1u
匹配 unsigned int
、int
和 bool
.
注意转换后的常量表达式不能包含收缩转换,int
到bool
是收缩,除非值是值0
或[=26=的常量表达式].所以 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&) {}
这很重要,因为重载决策可以根据函数参数生成 selection。来电:
unsigned int m;
h<1u>(m);
然后 h
的两个重载都进入重载决议,但是 h<unsigned int>
获胜,因为 h<bool>(m)
无效。
如上所述,调用h<42>(m);
在第一阶段获胜,因为它无法匹配h<bool>
;但在 MSVC++(和 g++)中,它错误地允许 h<bool>
在这个阶段通过,但稍后会像 h<1u>
情况一样修剪它。
相同模板函数的变体因非类型成员的类型不同是否有效?
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>
并希望确保常量值和目标值匹配。
---- mcve ----
#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++ 在非类型模板参数匹配方面都有错误,但它们 select 适合您的特定示例。
长答案:使用非类型模板参数重载函数模板是可以的。
然而,模板参数 与模板声明的匹配并不像预期的那样工作(无论如何是我)。所有匹配的模板都进入重载决议。它在任何阶段都不喜欢 "exact match".
根据 C++17 [temp.arg.nontype/]2,converted constant expressions 是允许的。这意味着,例如:
42
匹配int
和unsigned int
.42u
匹配int
和unsigned int
.1u
匹配unsigned int
、int
和bool
.
注意转换后的常量表达式不能包含收缩转换,int
到bool
是收缩,除非值是值0
或[=26=的常量表达式].所以 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&) {}
这很重要,因为重载决策可以根据函数参数生成 selection。来电:
unsigned int m;
h<1u>(m);
然后 h
的两个重载都进入重载决议,但是 h<unsigned int>
获胜,因为 h<bool>(m)
无效。
如上所述,调用h<42>(m);
在第一阶段获胜,因为它无法匹配h<bool>
;但在 MSVC++(和 g++)中,它错误地允许 h<bool>
在这个阶段通过,但稍后会像 h<1u>
情况一样修剪它。