Подтвердить что ты не робот

Как определить друзей в глобальном пространстве имен в другом пространстве имен С++?

Я хочу определить бинарный оператор в глобальном пространстве имен. Оператор работает над классом, который определен в другом пространстве имен, и оператор должен получить доступ к частным членам этого класса. Проблема в том, что я не знать, как обладать глобальным оператором, когда он делает его другом в определении класса.

Я пробовал что-то вроде:

namespace NAME
{
    class A {
        public:
            friend A ::operator * (double lhs, const A& rhs);
        private:
            int private_var;
    };
}

A operator * (double lhs, const A& rhs)
{
    double x = rhs.private_var;
    ...
}

Компилятор (g++ 4.4) не знал, что с ним делать. Кажется, что линия

friend A ::operator * ()

оценивается как нечто вроде (псевдокода)

(A::operator)

вместо

(A) (::operator)

Если я не укажу:: в объявлении оператора компиляция работает, но оператор находится в пространстве имен NAME, а не в глобальном пространстве имен.

Как я могу квалифицировать глобальное пространство имен в такой ситуации?

4b9b3361

Ответ 1

Во-первых, обратите внимание, что в вашей декларации оператора отсутствует квалификация пространства имен для A:

NAME::A operator * (double lhs, const NAME::A& rhs)

а затем решающим трюком является добавление круглых скобок в объявление друга, подобное этому, так же, как вы предложили в своем "псевдокоде"

friend A (::operator *) (double lhs, const A& rhs);

Чтобы все это скомпилировалось, вам понадобятся некоторые форвардные объявления:

namespace NAME
{
    class A;
}

NAME::A operator * (double lhs, const NAME::A& rhs);

namespace NAME
{
    class A {
        public:
            friend A (::operator *) (double lhs, const A& rhs);
        private:
            int private_var;
    };
}

NAME::A operator * (double lhs, const NAME::A& rhs)
{
    double x = rhs.private_var;
}

Александр прав, однако - вы должны, вероятно, объявить оператор в том же пространстве имен, что и его параметры.

Ответ 2

Это компиляция, я предполагаю, что без тестирования это также работает. Обратите внимание на использование круглых скобок:

namespace NAME {class A; }
NAME::A operator * (double lhs, const NAME::A& rhs);

namespace NAME
{
    class A {
        public:
            friend A (::operator *) (double lhs, const A& rhs);
        private:
            int private_var;
    };
}

NAME::A operator * (double lhs, const NAME::A& rhs)
{
    double x = rhs.private_var;
    return rhs;
}

int main() {}

Как отмечает Александр, ваш вопрос не объясняет, почему оператор не находится в пространстве имен NAME. В любом случае это можно назвать 1.0 * some_A_instance. Таким образом, вы можете создать ненужную проблему для себя.

Ответ 3

Я не знаю точного ответа на ваш вопрос.

Но ужасно плохая идея определить оператор за пределами пространства имен его параметров (теперь вы вырезаете зависимый от аргумента поиск, который очень полезен для операторов).

Ответ 4

Возможно - вы можете заключить декларатор в круглые скобки: friend A (::operator * (double lhs, const A& rhs));

Вам также нужно переслать-объявить как класс, так и функцию.

namespace NAME {class A;}
NAME::A operator *(double lhs, const NAME::A& rhs);

// ...

namespace NAME
{
    class A {
        public:
            friend A (::operator * (double lhs, const A& rhs));
        private:
            int private_var;
    };
}

NAME::A operator *(double lhs, const NAME::A& rhs) {
  //...
}

Но я согласен с Андреасом в том, что было бы лучше определить как в том же пространстве имен, если это возможно.