c++ - 使用额外的不可推导模板参数重载函数是否有效?
问题描述
以下代码可以编译并与 gcc (9)、clang (11) 和 msvc (16.28) 一起正常工作:
template <class A>
struct X {
A a;
constexpr X(A a) : a{a} { }
};
template <class A>
constexpr auto fn(X<A> const& x) {
return X<A>(x.a - 1);
}
template <class Xs, class A>
constexpr auto fn(X<A> const& x) {
return Xs(x.a - 1);
}
constexpr X<int> x1{3};
constexpr auto x2 = fn(x1);
constexpr auto x3 = fn<X<double>>(x1);
除了第二个中的额外参数外,有两个fn
函数具有相同的声明。Xs
我想确定这是标准接受的,而不是这些编译器额外提供的东西?由于所有 3 个都这样做,我猜这将是标准的,但你永远不知道。
我还想知道我对为什么这项工作/将成为标准的假设是否正确:
- 在通话
fn(x1)
中,Xs
不能推断出第二次重载fn
被轻轻丢弃(SFINAE?)? - 在调用
fn<Xs>(x1)
中,第一个重载将fn(X<X<int>>)
与参数不匹配x1
,因此第一个重载也被丢弃?
解决方案
除了第二个中的额外参数外,有两个
fn
函数具有相同的声明。Xs
没关系,您可以使用不同的参数或不同的模板参数重载函数模板。
- 在通话
fn(x1)
中,Xs
不能推断出第二次重载fn
被轻轻丢弃(SFINAE?)?
是的,除了它不是 SFINAE,而是重载决议。SFINAE 中的 S 代表替代。当不能推导出模板参数时,不会发生替换。
它在[temp.over]/1中有描述:
... 对于每个函数模板,如果参数推导和检查成功,则模板参数(推导和/或显式)用于合成单个函数模板特化的声明,该声明被添加到要使用的候选函数集在重载决议中。
关于第二个项目符号 ( fn<X<double>>(x1)
),两个模板都可以合成一个有效的声明,但X<int>
不能转换为X<X<double>>
,因此选择第二个重载作为唯一可行的重载。
注意:当多个模板重载可行时,将执行部分排序以确定最专业的模板。
推荐阅读
- reactjs - ReactJS 列表中的每个孩子都应该有一个唯一的“关键”道具不起作用
- c++ - 如何绘制像 Visual Studio 这样的关闭按钮?
- javascript - 无法从 db 渲染我的对象 - “对象不可迭代”
- android - 如何在flutter中使用存储权限?
- typescript - Vue Ruter 4 没有重载匹配这个调用。重载 1 of 3,给出以下错误
- javascript - 这个 clickHandler() 中的嵌套函数会是什么样子?
- terraform - 地形模块
- r - 用 smooth.spline 过冲
- python - 使用循环查找图中的所有连接节点
- html - CSS中隐藏子div时如何动态调整div的大小?