Что такое пространство имен определенной пользователем функции?
Если у меня есть функция, определенная как друг внутри класса. Каково пространство имен этой функции?
namespace A{namespace B{
struct S{
friend void f(S const&){};
};
}}
int main(){
A::B::S s{};
f(s); // ok
::f(s); // not ok, no f in global namespace
A::B::f(s); // no f in A::B
A::B::S::f(s); // not ok, no f in A::B::S
}
У него даже есть пространство имен? Имеет ли смысл иметь пространство имен?
Что делать, если я хочу устранить неоднозначность вызова в обычно используемой идиоме?
using std::swap;
swap(a, b);
Я вынужден определить это вне класса и объявить его другом?
3 ответа
Объявление друга относится к функции из самого узкого вмещающего пространства имен. Тем не менее, он не вводит имя этой функции в пространство имен
9.3.1.2 Определения членов пространства имен
3 Если объявление друга в нелокальном классе сначала объявляет класс, функцию, шаблон класса или шаблон функции, то друг является членом самого внутреннего окружающего пространства имен. Объявление друга само по себе не делает имя видимым для неквалифицированного или квалифицированного поиска.
http://eel.is/c++draft/namespace.memdef
Итак, в вашем случае A::B::f
это друг Тем не менее, имя f
не существует в A::B
еще. Вы не сможете ссылаться на это как A::B::f
пока вы не предоставите явное объявление f
в A::B
,
Имя поиска может найти f
в неквалифицированном f(s)
вызов через специальный механизм, называемый Argument Dependent Lookup (ADL). ADL - единственный механизм, который может "видеть" вашу функцию.
Функция находится в A::B
но его можно найти только через ADL или Koenig Lookup.
Единственный способ назвать его в main - это ввести его вне определения класса.
Да это странно
namespace A{namespace B{
inline void f(S const&);
struct S{
friend void f(S const&){};
};
}}
Сейчас A::B::f
имена f
,
Эту технику я использую для представления операторов и других точек настройки. Это также позволяет создавать функции экземпляра для каждого шаблона в классах шаблонов, которые сами не являются шаблонами.
template<class T>
struct foo {
friend void not_a_template( T ){}
};
template<class T>
void is_a_template(T){}
Да, вы определяете функцию снаружи и делаете ее другом определенного класса. Это абсолютно независимая функция, но вы разрешаете ей доступ к определенному классу.
Каждое имя, впервые объявленное в пространстве имен, является членом этого пространства имен. Если объявление друга в нелокальном классе сначала объявляет класс или функцию, класс или функция друга является членом внутреннего вложенного пространства имен.