开发者

How can I declare a friend function in a namespace that takes an inner class as a parameter?

开发者 https://www.devze.com 2023-04-12 01:23 出处:网络
Consider this code: namespace foo {} class A { class B { }; friend int foo::bar( B& ); }; namespace foo { int bar( A::B& )

Consider this code:

namespace foo {}

class A
{
   class B
   {
   };

   friend int foo::bar( B& );
};

namespace foo
{
   int bar( A::B& )
   {
   }
}

G++ 4.4.3 tells me:

friendfun-innerclass.cpp:21: error: 'int foo::bar(A::B&)' should have been declared inside 'foo'

But I can't declare:

namespace foo
{
   int bar( A::B& );
}

before the class A definition because A::B hasn't been declared. And I can't declare "class A::B" obviously, to declare class B I have to give the definition of class A, and as far as I know the "friend" declarations have to be inside the definition of class A.

What's strange to me is that if I take function "bar()" out of namespace foo everything works fine. It seems counterintuitive to me that having a function inside a namespace or 开发者_如何学Pythonnot inside a namespace changes whether the compiler will accept a friend function declaration in the class.

Does anybody know of a way to proprerly structure all the declarations and such to get this to work?


Can't be done the way you want to, because you would have to forward declare a nested class (which you can't) in order to provide a prototype for foo::bar.

As a first attempt to get around this problem, I would probably resort to making foo::bar a function template. That way the compiler will resolve the types after A and B are known.

Test harness:

namespace foo
{
    template<class B> int bar(B&);
};

class A
{
   class B
   {
       template<class B> friend int foo::bar( B& );
       int n_;
   public:
       B() : n_(42) {}
   };

public:
    B b_;
};

template<class B> int foo::bar(B& b)
{
    return b.n_;
}

int main()
{
    A a;
    foo::bar(a.b_);
}


I believe that you need ::foo::bar.


You can't because you can't forward-declare inner classes.

This is a close as you're gonna get.

namespace foo {
    class A_B;
    int bar(A_B &);
}

struct A
{
   class B
   {
   };

   friend int foo :: bar (A_B&);
};

namespace foo
{
   struct A_B : public A :: B {
     // constructors, delegated if you're C++11 :-)
   };

   int bar (A_B &)
   {
   }
}

You lose privatehood of A::B, but if you think about it, that makes sense, or you wouldn't be able to implement foo::bar.


It doesn't look like you can do that. What you can do is forward declare a class with a static member, and the class gets friendship. But any time you use friendship at least take one more look at your design and ask yourself why. It may be fine or there may be a better answer.

namespace foo { class bar; }

class A
{
   class B
   {
   };

   friend class ::foo::bar;
};

namespace foo
{
   class bar
   {
   public:
      static int run_bar( A::B& )
      {
      }
   };
}


You can't do it because there is no way to write a forward declaration of A::B and hence forward declare foo(A::B&).

However, you can use a trick known as "friend name injection" to declare (and possibly define) a friend function in the class definition. This way you can call that friend function without namespace qualifiers (e.g. bar(b) instead of foo::bar(b)) and argument-dependent lookup will successfully resolve the call:

struct A
{
    struct B {};

    friend int bar(B&) { // inject bar() into the outer namespace
        // implementation here
    }
};

namespace foo
{
   int foo()
   {
       A::B b;
       return bar(b); // it calls bar(B&) declared in A
   }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号