C++ Clang++ – Why operator() Copies Movable Temporaries in Clang and Understanding Copy Elision

c++c++23clangcopy-elisionexplicit-object-parameter

In the following C++23 program

struct A {
    A() {}
    A(A&&) = default;
    void f(this A) {}
    void operator() (this A) {}
};

int main() {
    A{}.f(); // ok
    A{}();   // Clang error
}

struct A is movable, and its member functions f() and operator() have explicit object parameter (this A).

In Clang compiler surprisingly A{}.f() works fine, but A{}() fails with the error:

<source>:10:5: error: call to implicitly-deleted copy constructor of 'A'
<source>:3:5: note: copy constructor is implicitly deleted because 'A' has a user-declared move constructor

Online demo: https://gcc.godbolt.org/z/hbfzMvE9f

Is there some difference between functions f() and operator() from the language standpoint that explains their observable treatment by the compiler?

Best Answer

This is a confirmed clang bug. The program is well-formed. The expression A{}() is equivalent to(interpreted as) A{}.operator()() which clang accepts. Since A{} is a prvalue(and hence an rvalue), the overloaded call operator A::operator()(this A) is a viable option here for the call A{}.operator()().

From over.call:

A function call operator function is a function named operator() that is a member function with an arbitrary number of parameters. It may have default arguments. For an expression of the form

postfix-expression ( expression-listopt )

where the postfix-expression is of class type, the operator function is selected by overload resolution ([over.call.object]). If a surrogate call function is selected, let e be the result of invoking the corresponding conversion operator function on the postfix-expression; the expression is interpreted as

e ( expression-listopt )

Otherwise, the expression is interpreted as

postfix-expression . operator () ( expression-listopt )