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

Dav*_*one 9 c++ language-lawyer c++-concepts c++20

该代码有效吗?

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

void g() {
    s<true>().f();
}
Run Code Online (Sandbox Code Playgroud)

clang 说是,但 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
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/f4Kb68aee

Bar*_*rry 8

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

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

唯一的参数是对象参数,我们之前有:

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

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

  • 对于某些参数j,是比 , 更好的转换序列,或者,如果不是这样,ICSj(F1)ICSj(F2)

我们可以为其提供更好的转换序列的唯一参数是对象参数,并且正如所确定的那样,该参数是等效的。所以这个决胜局不适用。

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

没有。

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

没有。

  • F1不是函数模板专业化,而是F2函数模板专业化,或者,如果不是这样,

没有。

  • F1F2是函数模板特化,并且根据 [temp.func.order] 中描述的部分排序规则,函数F1模板比​​模板更特化,或者,如果不是这样,F2

没有。

  • F1F2是具有相同参数类型列表的非模板函数,并且比 [temp.constr.order] 中描述的约束的部分排序F1受到更多约束F2,或者如果不是这样,

啊哈!在这个例子中,我们有具有相同参数类型列表的非模板函数(两者都是空的)。静态成员函数受约束,非静态成员函数不受约束,这是最简单的一种“更多约束”(请参阅​​ [temp.constr.order])。

因此,我认为 clang (和 msvc)接受该程序是正确的,而 gcc 拒绝它是错误的。(提交103783)。