相互依赖的本地类(或相互递归的lambdas)

时间:2013-11-28 03:52:39

标签: c++ class struct forward-declaration

我经常在方法中创建本地帮助器类,只要这样的类在本地有用但在方法之外无关紧要。我刚刚遇到一个案例,我想要两个相互依赖的本地类。

我们的想法是拥有以下模式:

void SomeClass::someMethod()
{
    struct A
    {
        B * b;
        void foo() { if(b) b->bar(); };
    };
    struct B
    {
        A * a;
        void bar() { if(a) a->foo(); }
    };
}

但由于A需要B,因此无法编译。前向声明B有帮助,以便行B * b;编译,但方法A::foo()仍然需要B的完整声明,并且编译器会抱怨。

我看到两个解决方法:

  1. SomeClass::someMethod()之前在SomeClass.cpp中声明和定义类。我觉得这不优雅,因为不仅SomeClass::someMethod()不是本地的课程,而且SomeClass都不是本地课程。

  2. 声明SomeClass.h中的类嵌套在SomeClass中,并在SomeClass.cpp中定义它们。我不喜欢这个解决方案,因为不仅类不是SomeClass::someMethod()的本地类,而且除了语言的限制外,它确实没有任何理由污染SomeClass.h。

  3. 因此有两个问题:是否可以让SomeClass::someMethod()的本地类成为可能?如果没有,你看到更优雅的解决方法吗?

2 个答案:

答案 0 :(得分:1)

实施虚拟A,供B使用,然后实现真正的A.

struct virtA
{
  virtual void foo() = 0 ;
} ;
struct B
{
  virtA * a ;
  void bar() { if ( a) { a->foo() ; } }
} ;
struct A : public virtA
{
  B * b ;
  void bar() { if ( b) { b-> bar() ; } }
} ;

答案 1 :(得分:0)

由于答案似乎是:“不可能拥有干净的相互依赖的本地类”,事实证明我最喜欢的解决方法是将逻辑移到结构本身之外。正如remyabel在问题的评论中所建议的,它可以通过创建第三个类来完成,但我最喜欢的方法是创建相互递归的lambda函数,因为它可以捕获变量(因此在我的实际情况下使我的生活更轻松)用法)。所以它看起来像:

#include <functional>
#include <iostream>

int main()
{
    struct B;
    struct A { B * b; };
    struct B { A * a; };

    std::function< void(A *) > foo;
    std::function< void(B *) > bar;

    foo = [&] (A * a) 
    {
        std::cout << "calling foo" << std::endl;
        if(a->b) { bar(a->b); }
    };
    bar = [&] (B * b)
    {
        std::cout << "calling bar" << std::endl;
        if(b->a) { foo(b->a); }
    };

    A a = {0};
    B b = {&a};
    foo(&a);
    bar(&b);

    return 0;
}

编译并打印:

calling foo
calling bar
calling foo

请注意,必须手动指定lambdas的类型,因为类型推断不适用于递归lambda。