[C++] Объясните плиз в чем ошибка

erotic

Почему в Vusial Studio 9.0
 namespace aa {
class A
{
struct ZZ
{
int z;
};

friend void zz_out(const ZZ& zz);
};
// указывать необязательно, разницы нет
void zz_out(const A::ZZ& z);
}// aa

void aa::zz_out(const aa::A::ZZ& z)
{
}

Не компилируется с ошибкой
error C2248: 'aa::A::ZZ' : cannot access private struct declared in class 'aa::A'

, а
 
namespace aa {
class A
{
struct ZZ
{
int z;
};

friend void zz_out(const ZZ& zz);
};
void zz_out(const A::ZZ& z)
{
}
}// aa


компилируется нормально? В gcc первый вариант компилируется, поэтому мне кажется, что это косяк визуалки.

trobak

Наверное, проблемы в том, что компилятор не понял, в каком неймспейсе сидит дружественная zz_out - в глобальном или в aa.
Попробуй, что ли явно ее неймспейс указать
friend void aa::zz_out(const ZZ& zz);
вдруг поможет.

erotic

Я не могу этого сделать, т.к. в момент объявления функции другом ее еще нет в aa. Я не могу объявить эту функцию раньше объявления класса A, поскольку в ее определении используется внутренняя структура ZZ, которую я не могу предварительно объявив. Т.е. я хотел сделать так:
 
namespace aa {
class A;
struct A::ZZ;
void zz_out(const A::ZZ& z);


но так нельзя.

kokoc88

Да, либо косяк, либо ждём тех, кто читает стандарт перед сном.
А зачем тебе вообще так делать? Какую задачу решаешь?

sbs-66

Насколько я понял, выражение
void aa::zz_out(const aa::A::ZZ& z)
{
}

не помещает тело функции в namespace aa. Ну, чего-то то там у него не переключается, и он её не асоциирует с тем, что обьявлено как friend. Надо писать вот так:
namespace aa {
void zz_out(const A::ZZ& z)
{
}
}

erotic

Конечно, такое выражение не только не помещает функцию в aa, но еще и ошибочно без предварительного объявления функции внутри namespace aa{}. Но объявление функции как friend одновременно служит и объявлением функции в охватывающей области видимости (в данном случае в aa). Я не знаю, соответствует ли такое поведению стандарту и реализовано ли во всех компиляторах, но для двух версий MSVC и gcc это так.
Тем не менее, в первом примере я ввожу объявление функции zz_out в пространство имен aa, это можно увидеть, если внимательно посмотреть. А уже определение пишу отдельно.

erotic

А зачем тебе вообще так делать? Какую задачу решаешь?
Есть класс, который внутри себя использует объявленный там же enum. Кроме самого класса это тип никому не интересен, т.ч. открывать его не вижу смысла.
Для него я хочу иметь операторы вывода в поток, но я не могу объявить их внутри класса как istream& operator << (istream& s, MyEnum& obj т.к. при объявлении внутри класса операторы << и >> могут иметь всего лишь один параметр (т.е. служить для вывода всего класса в поток и ввода из него). Т.ч. приходится делать friend. Ну может быть еще объявить операторы static получится, и тогда можно будет два параметра передавать, но я так делать не пробовал.

sbs-66

тем не менее мой вариант компилируется, а твой - нет. 8)

erotic

тем не менее мой вариант компилируется, а твой - нет. 8)
Собственно, в этом и суть вопроса ;)

sbs-66

Ну считай, что это глюк визуалки. В чём проблема, если есть рабочее решение?
Оставить комментарий
Имя или ник:
Комментарий: