взаимозависимые локальные классы (или взаимно рекурсивные лямбды)

0

Я часто создаю локальные вспомогательные классы внутри методов, везде, где такой класс локально полезен, но не имеет значения вне метода. Я просто наткнулся на случай, когда мне хотелось бы, чтобы два локальных класса были взаимозависимыми.

Идея состоит в следующем:

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.cpp, до SomeClass::someMethod(). Я чувствую, что это не изящно, поскольку не только классы не являются локальными для SomeClass::someMethod(), но даже не локальны для SomeClass.

  2. Объявление классов в SomeClass.h, вложенных в SomeClass, и определение их в SomeClass.cpp. Мне не нравится это решение либо потому, что не только классы не являются локальными для SomeClass::someMethod(), но он загрязняет SomeClass.h без уважительной причины, кроме ограничения языка.

Отсюда два вопроса: возможно ли вообще, чтобы классы были локальными для SomeClass::someMethod()? Если нет, вы видите более элегантные обходные пути?

  • 0
    зачем вам это нужно внутри метода? Вы можете объявить / определить их только в файле .cpp, и это не загрязняет файл .h
  • 0
    @BryanChen: на самом деле это не то, что мне нужно , просто, если я могу, это намного элегантнее: если класс является подробностями реализации метода, то определение его внутри метода - это то место, где он принадлежит. Просто хорошая ООП инкапсуляция.
Показать ещё 6 комментариев
Теги:
class
struct
forward-declaration

2 ответа

0
Лучший ответ

Поскольку ответ кажется: "невозможно иметь чистые взаимозависимые локальные классы", оказывается, что обходной путь, который мне больше всего нравится, - это перемещать логику вне самих структур. Как было предложено remyabel в комментариях к этому вопросу, это можно сделать, создав третий класс, но мой любимый подход - создать взаиморекурсивные лямбда-функции, поскольку он позволяет захватывать переменные (следовательно, делает мою жизнь проще в моем реальном случае Применение). Так выглядит:

#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 должен быть указан вручную, поскольку вывод типа не работает с рекурсивными лямбдами.

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() ; } }
} ;
  • 0
    Ах, хорошо, тогда мы должны немного поднять ужас.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню