Search code examples
c++gcccompiler-errorsc++17friend-function

Is it a bug of C++ gcc HEAD 10.0.0 20190 relative to friend functions


The following program compiles with using clang HEAD 10.0.0

#include <iostream>

template <class T>
void f( const T & );

class A
{
public:
    A( int x = 0 ) : x( x ) {}

    friend void ::f( const A & );
private:
    int x;
};

template <class T>
void f( const T &t )
{
    std::cout << "t.x = " << t.x << '\n';
}


int main()
{
    A a( 10 );
    f( a );
}

The program output is

t.x = 10

But when the gcc HEAD 10.0.0 20190 compiler is used then it outputs the error

prog.cc:11:32: error: 'void f(const A&)' should have been declared inside '::'
   11 |     friend void ::f( const A & );
      |                                ^ 

Is it a bug of the compiler or am I doing something wrong?


Solution

  • Filed 91618.


    [temp.friend]/1 reads:

    A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class. For a friend function declaration that is not a template declaration:

    • if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise,
    • if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,
    • if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template ([temp.deduct.decl]), otherwise,
    • the name shall be an unqualified-id that declares (or redeclares) a non-template function.

    That third bullet should allow this:

    template <class T> void f(T);
    
    struct A {
        friend void ::f(A);
    };
    

    ::f is a qualified-id and a matching function template is found, so it should work. But gcc requires us to write ::f<>, which is a template-id, in order to adhere to the first bullet.