Как определить друзей в глобальном пространстве имен в другом пространстве имен C ++? - PullRequest
13 голосов
/ 05 февраля 2010

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

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

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, а не в глобальном пространстве имен.

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

Ответы [ 4 ]

15 голосов
/ 05 февраля 2010

Во-первых, обратите внимание, что в объявлении вашего оператора отсутствует квалификация пространства имен для 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;
}

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

4 голосов
/ 05 февраля 2010

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

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 голосов
/ 05 февраля 2010

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

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

2 голосов
/ 05 февраля 2010

Возможно - вы можете заключить декларатор в скобки: 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) {
  //...
}

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

...