简体   繁体   中英

C++ 17 friend function declaration and inline namespace

Consider the following program

#include <iostream>

namespace N1
{
    inline namespace N2
    {
        class A
        {
        public:
            friend void f( const A & );
        private:
            int x = 10;
        };

        //void f( const A & );
    }

    void N2::f( const A &a ) { std::cout << a.x << '\n'; }
}

int main()
{
    using namespace N1;

    A a;

    f( a );
}    

According to the C++ 17 Standard (10.3.1.2 Namespace member definitions)

3 If a friend declaration in a non-local class first declares a class, function, class template or function template97 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (6.4.1) or qualified lookup (6.4.3).

So the name of the friend function is invisible in the namespace N2. So it also should be invisible in the namespace N1.

However the code is compiled and executed without warnings by the clang HEAD 10.0.0 .

The compiler gcc HEAD 10.0.0 20191 issues warnings

prog.cc:18:10: warning: 'void N1::N2::f(const N1::N2::A&)' has not been declared within 'N1::N2'
   18 |     void N2::f( const A &a ) { std::cout << a.x << '\n'; }
      |          ^~
prog.cc:10:25: note: only here as a 'friend'
   10 |             friend void f( const A & );
      |                         ^

but runs the program and the correct result is outputted.

Visual C++ 2019 also compiles the code successfully without warnings and the program outputs the expected result.

Is there a bug of the three compilers because the name f is invisible so the definition of the friend function f in the enclosing namespace is incorrect?

As I mentioned in my comment, the function bodies and the parameter of f are not really relevant since the issue is only with the name lookup of N2::f . After removing them, it also doesn't matter whether the namespace N2 is inline or not. All compilers behave the same way in either case.

GCC warns, but gives a hard error with -pedantic-errors on the definition of N2::f . MSVC and Clang always accept the code without diagnostic.

I think you are right, that going by the wording N2::f in the function definition declarator should be looked up by qualified name lookup rules, which should not find the friend declaration without an intervening declaration of f at N2 's scope, not using a qualified name.

However there is defect report 1477 which seems to have had the intention of making such an out-of-namespace definition well-formed.

In the open CWG issue 1900 this question is reposed and the issue description also concludes that the normative text of the standard does not allow the definition. It also notes that there is implementation variance, as you are observing.

For Clang, there is a bug report about a similar case here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM