【问题标题】:Is it valid to overload function with extra non-deducible template parameter?使用额外的不可推导模板参数重载函数是否有效?
【发布时间】:2021-10-12 22:38:59
【问题描述】:

以下代码可以编译并与 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&lt;Xs&gt;(x1) 中,第一个重载将是fn(X&lt;X&lt;int&gt;&gt;),它与参数x1 不匹配,因此第一个重载也被丢弃?

【问题讨论】:

  • 大多数情况下,拒绝第二次重载的不是 SFINAE,因为甚至没有替换。

标签: c++ templates language-lawyer


【解决方案1】:

有两个 fn 函数具有相同的声明,除了第二个中的额外 Xs 参数。

没关系,你可以使用不同的参数或不同的模板参数重载函数模板。

  • 在调用fn(x1) 中,Xs 无法推断出,所以fn 的第二个重载被轻轻丢弃(SFINAE?)?

是的,除了它不是 SFINAE,而是重载解析。 SFINAE 中的 S 代表替代。当不能推导出模板参数时,不会发生替换。

[temp.over]/1中有描述:

...对于每个函数模板,如果参数推导和检查成功,模板参数(推导和/或显式)用于合成声明添加到要在重载分辨率中使用的候选函数集的单个函数模板特化。

关于第二个项目符号 (fn&lt;X&lt;double&gt;&gt;(x1)),两个模板都可以合成一个有效的声明,但 X&lt;int&gt; 不能转换为 X&lt;X&lt;double&gt;&gt;,因此选择第二个重载作为唯一可行的。

注意:当多个模板重载可行时,会执行partial ordering 以确定最专业的模板。

【讨论】:

  • 谢谢,由于“不可替代”,我很确定这不是 SFINAE。如果我理解这句话,这意味着在fn(x1) 中,您可以从第一个重载中合成fn&lt;int&gt;(X&lt;int&gt;),但您无法从第二个重载中合成任何内容,因为您无法推断出Xs,而在fn&lt;X&lt;int&gt;&gt;(x1) 中,您可以同时合成@ 987654335@ 和 fn&lt;X&lt;int&gt;, int&gt;(X&lt;int&gt;) 并且只有第二个重载匹配,对吧?
  • 当多个重载可行时,无论模板特化与否,它们首先根据转换序列进行比较。只有当这种比较产生粗略地说“同样好”的结果时,我们才能达到决胜局,其中之一是偏序。
  • 有趣的是,如果第二个调用是fn&lt;X&lt;int&gt;&gt;(x1),在这种情况下这将是可见的。在这种情况下,两个重载都是可行的,因为第一个重载有从X&lt;int&gt;X&lt;X&lt;int&gt;&gt; 的转换,但第二个有更好的转换(身份),所以选择了第二个。即使根据偏序规则,没有一个模板比另一个模板更专业,也会发生这种情况。抄送@霍尔特
猜你喜欢
  • 2022-12-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 2011-09-15
  • 1970-01-01
相关资源
最近更新 更多