使用额外的不可推导模板参数重载函数是否有效?

以下代码在 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>>,因此选择第二个重载作为唯一可行的一个。

注意:当多个模板重载可行时,将执行偏序以确定最专业的模板。


以上是使用额外的不可推导模板参数重载函数是否有效?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>