Рассмотрим следующую программу
#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 );
}
В соответствии со стандартом C ++ 17 (определения членов пространства имен 10.3.1.2)
3 Если объявление друга в нелокальном классе сначала объявляет класс, функцию, шаблон класса или шаблон функции97, то друг является членом самого внутреннего включающего пространства имен. Объявление друга само по себе не делает имя видимым для неквалифицированного поиска (6.4.1) или квалифицированного поиска (6.4.3).
Таким образом, имя функции друга невидимо в пространстве имен N2. Так что он также должен быть невидимым в пространстве имен N1.
Однако код компилируется и выполняется без предупреждений clang HEAD 10.0.0.
Компилятор gcc HEAD 10.0.0 20191 выдает предупреждения
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 & );
| ^
но запускает программу и выводит правильный результат.
Visual C ++ 2019 также успешно компилирует код без предупреждений, и программа выводит ожидаемый результат.
Есть ли ошибка трех компиляторов, потому что имя f
невидимо, поэтому определение функции друга f
во включающем пространстве имен неверно?
-pedantic-errors
, поэтому, похоже, предполагается, что код неправильно сформирован в соответствии со стандартом. Ошибка связана с определением, поэтому телоmain
на самом деле не имеет значения. Иinline
тоже. Без него все компиляторы ведут себя одинаково. - person walnut   schedule 18.12.2019