下列program https://godbolt.org/z/f43EK4PnY从此代码中减少question https://stackoverflow.com/questions/66740188:
template <typename T, void (*)(T), typename = void>
struct S;
template <typename T, void (*f)(T)>
struct S<T, f, void> {};
S<int const, nullptr> s;
在 GCC 的所有版本中,在所有语言修订版中,专业化S
被选择时s
被实例化。
在 Clang 的所有版本中,但仅从 C++17 开始,在实例化时选择主模板s
.
我认为值得注意的一些要点是,如果实例化结束,则永远不会选择主数据库<int, nullptr>
,即第一个参数不再是int const
。此外,如果第二个参数中函数指针的签名不包含,则永远不会选择主函数T
作为参数,即如果第二个参数是T (*)()
, or void (*)()
, say.
如果这段代码不是 IFNDR,哪个编译器是正确的? C++17 语言修订版中有一些重大变化吗?
这是因为 C++17 允许从非类型参数的类型推导模板类型参数。[温度扣除类型]/13 https://timsong-cpp.github.io/cppwp/temp.deduct.type#13:
当参数的值对应于非类型模板时
范围P
使用依赖类型声明的值是从
一个表达式,模板参数的类型P
被推论出
从值的类型来看。
所以当我们尝试匹配时S<int const, nullptr>
针对偏特化,我们推导出偏特化的模板参数T
来自两个来源:
- 从第一个模板参数
int const
,我们推论T
= int const
- 从第二个模板参数(其类型为
void (*)(int)
因为函数参数的顶级 cv 限定被调整掉了),我们推导出T
= int
.
由于我们推导出了相互矛盾的结果,因此推导失败并且部分特化不匹配。
早在 2019 年,核心反射器就提出了类似的例子。人们一致认为这是标准中的一个缺陷,并且从非类型模板参数的类型中进行推导应该只发生在那些无法以其他方式推导的事情上。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)