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

发布于 2024-12-09 09:55:00 字数 640 浏览 0 评论 0原文

考虑这段代码:

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 尚未声明。显然,我不能声明“class A::B”,要声明类 BI 必须给出类 A 的定义,并且据我所知,“friend”声明必须位于类 A 的定义内

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

有谁知道如何正确构建所有声明等以使其发挥作用?

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 not 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

只有一腔孤勇 2024-12-16 09:55:00

无法按照您想要的方式完成,因为您必须转发声明嵌套类(你不能),以便为 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_);
}

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_);
}
远山浅 2024-12-16 09:55:00

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

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

多孤肩上扛 2024-12-16 09:55:00

你不能,因为你不能前向声明内部类。

这就是你将要得到的结束。

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

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.

他不在意 2024-12-16 09:55:00

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

namespace foo { class bar; }

class A
{
   class B
   {
   };

   friend class ::foo::bar;
};

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

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& )
      {
      }
   };
}
一场信仰旅途 2024-12-16 09:55:00

您不能这样做,因为无法编写 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
   }
}

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
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文