C++ friend function и namespace

187
29 декабря 2018, 07:20

file.cpp

#include "file.h"
namespace NS
{
 void f(const A &obj)
 {
   std::cout << obj.data;
 }
}

file.h

class A
{
 private: int data;
 friend void NS::f(const A &obj);
}

Компилятор на это ругается. Если описать NS в file.cpp до class A, то все работает. Подскажите, пожалуйста, чего я не понимаю? Почему так происходит? Как сделать так, чтобы работало, когда NS в другом файле?

UPD: и в одном файле не работает. "Использование неопределенного типа А"

Answer 1

Исправляется это так:

file.cpp остается без изменений.

В file.h пишется вот что:

class A;
namespace NS
{
    void f(const A &obj);
}
class A
{
  private:
    int data;
    friend void NS::f(const A &obj);
}

Почему ваш вариант не работал?

Во-первых, компилятору не было известно, что такое NS: пространство имен или класс, или еще что-то.

Однако даже если добавить над классом namespace NS {}, работать все равно не будет, но в этот раз ошибка будет другая: error: 'void NS::f(const A&)' should have been declared inside 'NS' (c) GCC.

Будь f в том же пространстве имен, что и класс, friend void f(const A &); сработало бы без объявления функции. (Эта строчка сама была бы объявлением функции, хотя до нормального (пере)объявления ее можно было бы достать только через argument-dependent lookup.)

Почему так? Видимо разработчики стандарта решили, что объявлять функции в произвольных пространствах имен из классов в других пространствах имен - это перебор.

Answer 2

В языке С++ квалифицированные имена, вроде NS::f, используются только для ссылки на уже ранее объявленные, т.е. уже известные компилятору сущности. Хотите использовать квалифицированное имя - позаботьтесь о том, чтобы сущность, на которую это имя ссылается, была объявлена заранее. Упрощенно выражаясь, такие сущности должны быть объявлены выше по файлу.

Answer 3

Использовать дружбу с функцией можно, если только объявлена эта функцию заблаговременно. Объявлять функцию можно, но заблаговременно нужно объявить класс. Неважно в каком файле вы это будете делать, главное порядок.

# include <iostream>
class A;
namespace NS{
void f(const A &obj);  }
class A
{
 private: int data;
 friend void NS::f(const A &obj);
};
namespace NS {
 void f(const A &obj) {
   std::cout << obj.data; } }
READ ALSO
C++ wndproc в классе

C++ wndproc в классе

Делаю обертку вокруг winapi окна, нужно затащить wndproc в класс а он статическийВобщем WindowProc не работает почемуто

196
Netbeans (C/C++) + Базы данных. Как подключить любую СУБД?

Netbeans (C/C++) + Базы данных. Как подключить любую СУБД?

Нужно подключить любую СУБД к проекту Netbeans (C++, MinGW)Провёл день в попытках подключить MySQL, так и не найдя нигде инструкции или документации

180
Почему у функции scanf_s в Visual Studio при использовании &ldquo;%s&rdquo; прекращается работа в языке Си

Почему у функции scanf_s в Visual Studio при использовании “%s” прекращается работа в языке Си

Почему у функции scanf_s в Visual Studio 2013 при использовании "%s" прекращается работа в языке Си

198