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

Overloading static and non-static member function with constraint

此代码有效吗?

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

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

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

https://godbolt.org/z/f4Kb68aee

如果我们遍历 [over.match.best.general],我们得到:

a viable function F<sub>1</sub> is defined to be a better function than another viable function F<sub>2</sub> if for all arguments i, ICS<sub>i</sub>(F<sub>1</sub>) is not a worse conversion sequence than ICS<sub>i</sub>(F<sub>2</sub>), and then [...]

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

If F is a static member function, ICS<sub>1</sub>(F) is defined such that ICS<sub>1</sub>(F) is neither better nor worse than ICS<sub>1</sub>(G) for any function G, and, symmetrically, ICS<sub>1</sub>(G) is neither better nor worse than ICS<sub>1</sub>(F); otherwise,

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

  • for some argument j, ICS<sub>j</sub>(F<sub>1</sub>) is a better conversion sequence than ICS<sub>j</sub>(F<sub>2</sub>), or, if not that,

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

  • the context is an initialization by user-defined conversion (see [dcl.init], [over.match.conv], and [over.match.ref]) and [...]

没有。

  • the context is an initialization by conversion function for direct reference binding of a reference to function type, [...]

没有。

  • F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

没有。

  • F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,

没有。

  • F1 and F2 are non-template functions with the same parameter-type-lists, and F1 is more constrained than F2 according to the partial ordering of constraints described in [temp.constr.order], or if not that,

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

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

根据 C++20 标准,您的代码格式错误class.static.mfct#2

There shall not be a static and a non-static member function with the same name and the same parameter types ([over.load]).

这里也不例外,也有requires子句来区分成员函数,只是名称相同,参数类型相同。而这正是我们的情况:相同的名称是f,相同的参数类型是空集。

所以Clang和MSVC在接受代码时是错误的。但是 GCC 的诊断肯定是混乱的。

通过对代码进行一些小的调整(删除非静态成员函数中的 const 并在代码中获取其地址),Clang 和 MSVC 也显示出大问题:

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

int main() {
    s<true>().f();
    void (s<true>::*x)() = &s<true>::f;
}

演示:https://gcc.godbolt.org/z/vdq9j63Gs