使用约束重载静态和非静态成员函数

2022-05-16 00:00:00 language-lawyer c++ c++20 c++-concepts

此代码有效吗?

template<bool b>
struct s {
    void f() const {
    }
    static void f() requires b {
    }
};

void g() {
    s<true>().f();
}

啪的一声说是,GCC说不是

<source>: In function 'void g()':
<source>:10:20: error: call of overloaded 'f()' is ambiguous
   10 |         s<true>().f();
      |         ~~~~~~~~~~~^~
<source>:3:14: note: candidate: 'void s<b>::f() const [with bool b = true]'
    3 |         void f() const {
      |              ^
<source>:5:21: note: candidate: 'static void s<b>::f() requires  b [with bool b = true]'
    5 |         static void f() requires b {
      |                     ^
Compiler returned: 1

https://godbolt.org/z/f4Kb68aee


解决方案

如果我们通过[over.match.best.general],我们将获得:

一个可行函数F1被定义为比另一个可行函数F2好的函数,如果对于所有参数iICSi(F1)不是比ICSi(F2)更差的转换序列,然后[...]

唯一的参数是Object参数,我们在前面有过:

如果F是静态成员函数,则ICS1(F)被定义为对于任何函数ICS1(F)既不比ICS1(G)好也不比ICS1(G)差,并且对称地,ICS1(G)既不比ICS1(F)好也不比ICS1(F)差;否则

因此前提成立:一个函数的所有参数的转换序列不比另一个函数的转换序列差。所以我们进入决胜局...

  • 对于某些参数jICSj(F1)是比ICSj(F2)更好的转换序列,如果不是这样,
我们可以有更好的转换序列的唯一参数是对象参数,正如所确定的那样,该参数是等价的。因此,此决胜局不适用。

  • 上下文是通过用户定义的转换(参见[dcl.init]、[over.match.conv]和[over.match.ref])和[...]
  • 进行的初始化

没有。

  • 上下文是转换函数的初始化,用于直接引用绑定到函数类型的引用,[...]

没有。

  • F1不是函数模板专门化,F2是函数模板专门化,否则

没有。

  • F1F2是函数模板专门化,根据[temp.unc.order]中描述的偏序规则,F1的函数模板比F2的模板专门化,如果不是这样,

没有。

  • F1F2是具有相同参数类型列表的非模板函数,根据[temp.constr.order]中描述的约束的部分顺序,F1F2更受约束,如果不是这样,

啊哈!在本例中,我们的非模板函数具有相同的参数类型列表(两者都是空的)。静态成员函数受约束,而非静态成员函数不受约束,这是受约束程度最低的一种(请参阅[temp.constr.order])。

因此,我认为Cang(和MSVC)接受这个计划是正确的,GCC拒绝它是错误的。(已提交103783)。

相关文章