Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading static and non-static member function with constraint

Is this code valid?

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

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

clang says yes, but gcc says no

<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

like image 909
David Stone Avatar asked Dec 21 '21 00:12

David Stone


People also ask

Can static member function be overloaded?

2) Member function declarations with the same name and the name parameter-type-list cannot be overloaded if any of them is a static member function declaration.

What happens if non static members are used in static member function?

What happens if non static members are used in static member function? Explanation: There must be specific memory space allocated for the data members before the static member functions uses them. But the space is not reserved if object is not declared.

Can we overload static member functions in C++?

Function declarations that differ only in the return type cannot be overloaded. Member function declarations with the same name and the same parameter types cannot be overloaded if any of them is a static member function declaration (9.4).

What is static and non static member function in C++?

A static member function can be called, even when a class is not instantiated. A static member function cannot have access to the this pointer of the class. A non-static member function can be declared as virtual but care must be taken not to declare a static member function as virtual.

Can a member function be overloaded?

Function declarations that differ only in the return type cannot be overloaded. Member function declarations with the same name and the same parameter types cannot be overloaded if any of them is a static member function declaration (9.4).

How to take an object parameter in a non static member function?

A non-static member function can be declared to take as its first parameter an explicit object parameter, denoted with the prefixed keyword this . For template member functions, explicit object parameter allows deduction of type and value category, this language feature is called "deducing this "

How to overload member methods in C++?

C++ allows member methods to be overloaded on the basis of const type. Overloading on the basis of const type can be useful when a function return reference or pointer.

How are non-static member functions treated during overload resolution?

During overload resolution, non-static member function with a cv-qualifier sequence of class X is treated as follows: no ref-qualifier: the implicit object parameter has type lvalue reference to cv-qualified X and is additionally allowed to bind rvalue implied object argument


Video Answer


2 Answers

If we go through [over.match.best.general], we get:

a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then [...]

The only argument is the object argument, and we have earlier that:

If F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,

So the premise holds: all arguments for one function have a conversion sequence no worse than the conversion sequence for the other function. So we move on to our tiebreakers...

  • for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

The only argument that we could have a better conversion sequence for is the object argument, and as established, that one is equivalent. So this tiebreaker does not apply.

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

Nope.

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

Nope.

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

Nope.

  • 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,

Nope.

  • 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,

Aha! In this example, we have non-template functions with the same parameter-type-lists (both are just empty). The static member function is constrained and the non-static member function is not constrained, which is the most trivial kind of "more constrained" (see [temp.constr.order]).

As such, I think that clang (and msvc) are correct to accept the program and gcc is incorrect to reject it. (submitted 103783).

like image 144
Barry Avatar answered Oct 21 '22 07:10

Barry


Your code is ill-formed according to C++20 standard 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]).

There is no exception here for the presence of requires-clause to differentiate member functions, only same name and the same parameter types. And it is exactly our case: the same name is f, and the same parameter types is empty set.

So Clang and MSVC are wrong in accepting the code. But the diagnostics of GCC is definitely confusing.

With some minor tweaks in the code (removed const in not-static member function and get its address in the code), Clang and MSVC also show to have big problems with it:

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

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

Demo: https://gcc.godbolt.org/z/vdq9j63Gs

like image 41
Fedor Avatar answered Oct 21 '22 08:10

Fedor