views:

423

answers:

5

Hi,

I'd like to define a binary operator on in the global namespace. The operator works on a class that is defined in another namespace and the operator should get access to the private members of that class. The problem I have is that I don't know how to scope that global operator when making it a friend in the class definition.

I tried something like:

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;
    ...
}

The compiler (g++ 4.4) didn't know what to do with it. It seems that the line

friend A ::operator * ()

is evaluated as something like (pseudo-code)

(A::operator)

instead of

(A) (::operator)

If I leave out the :: in the declaration of the operator the compiling works but the operator is then in namespace NAME and not in the global namespace.

How can I qualify the global namespace in such a situation?

+4  A: 

I don't know exact answer to your question.

But it's terrible bad idea to define operator outside namespace of its parameters (now you cut argument dependent lookup which is very usable for operators).

Alexander Poluektov
+1. While this answer cuts to the root of the issue, one slight nitpick: if the op* is at global scope, then you don't need ADL, as the function is always available. (I'm not sure, but maybe the OP didn't understand ADL and thus came up with this?)
Roger Pate
+4  A: 

This compiles, I assume without testing that it also works. Note the use of parentheses:

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() {}

As Alexander mentions, though, your question doesn't explain why the operator isn't in namespace NAME. Either way it can be called as 1.0 * some_A_instance. So you may be creating needless trouble for yourself.

Steve Jessop
Darn, you beat me to it by about 20 seconds. Almost identical code too.
finnw
That makes us three now, I guess...
Martin B
Great, you saved my day. I wasn't aware of the fact that the operator can reside in NAME and still work the way I wanted.
Andreas
+2  A: 

It is possible - you can enclose the declarator in parentheses: friend A (::operator * (double lhs, const A& rhs));

You also need to forward-declare both the class and the function.

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) {
  //...
}

But I agree with Andreas that it would be better to define both in the same namespace if possible.

finnw
+1  A: 

First, note that your operator declaration was lacking a namespace qualification for A:

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

and then the decisive trick is to add parentheses to the friend declaration like this, just as you proposed in your "pseudo-code"

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

To make it all compile, you then need some forward declarations, arriving at this:

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;
}

Alexander is right, though -- you should probably declare the operator in the same namespace as its parameters.

Martin B
That's 3 nearly-identical answers now :-)
finnw
Surely, you mean *only* three :)
A: 

OK, that solves the problem for a function. What about for a friend class?

Same problem: class G in global namespace; class A in namespace DD; A wants to let G see its private members.

class G;

namespace DD { class A { friend class G; // <-- gets put in namespace G private: int m_foo; }; };

I have found no way to tell g++ to use class G from the global namespace.

Dan Dietterich