如何在以内部类作为参数的命名空间中声明友元函数?

时间:2011-10-11 15:20:33

标签: c++ inner-classes forward-declaration friend-function

考虑以下代码:

namespace foo {}

class A
{
   class B
   {
   };

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

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

G ++ 4.4.3告诉我:

  

friendfun-innerclass.cpp:21:错误:'int foo :: bar(A :: B&)'应该有   在'foo'中声明了

但我无法宣布:

namespace foo
{
   int bar( A::B& );
}
在A类定义之前

因为A :: B尚未声明。而且我不能明确声明“类A :: B”,声明类BI必须给出类A的定义,据我所知,“朋友”声明必须在类A的定义中。 / p>

对我来说很奇怪的是,如果我从命名空间foo中取出“bar()”函数,一切正常。对我来说似乎违反直觉的是,在命名空间内部或不在命名空间内部使用函数会改变编译器是否接受类中的友元函数声明。

有没有人知道如何通过这种方式来构建所有声明,以便让它发挥作用?

5 个答案:

答案 0 :(得分:3)

无法按照您希望的方式完成,因为您必须转发声明嵌套类(which you can't)才能为foo::bar提供原型。

作为解决此问题的第一次尝试,我可能会使foo::bar成为一个功能模板。这样,编译器将在AB已知后解析类型。

测试工具:

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

答案 1 :(得分:0)

我相信您需要::foo::bar

答案 2 :(得分:0)

你不能,因为你不能转发声明内部类。

这是一个接近,因为你会得到。

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

你失去了A::B的私密性,但是如果你考虑它,这是有道理的,或者你将无法实现foo::bar

答案 3 :(得分:0)

看起来你不能这样做。你可以做的是向前声明一个带有静态成员的类,并且该类获得友谊。但是,任何时候你使用友谊至少再看看你的设计并问自己为什么。它可能没问题,或者可能有更好的答案。

namespace foo { class bar; }

class A
{
   class B
   {
   };

   friend class ::foo::bar;
};

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

答案 4 :(得分:0)

你不能这样做,因为没有办法写出A::B的前瞻性声明,因此转发声明foo(A::B&)

但是,您可以使用称为“朋友名称注入”的技巧来在类定义中声明(并可能定义)友元函数。这样,您可以在没有命名空间限定符的情况下调用该友元函数(例如bar(b)而不是foo::bar(b)),并且依赖于参数的查找将成功解析调用:

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