重构模板 class,使用它的嵌套 class 作为另一个 class 的模板参数

Refactor template class that uses it's nested class as a template argument for another class

在重构代码以便于对现有代码库进行单元测试时,我发现了一个如下所示的代码片段:

template <typename T>
class B {
 public:
  B(T* t) : t_(t) {}
  void do_that() { t_->do_abc(); }

 private:
  T* t_;
};

template <typename T1, typename T2>
class A {
 public:
  class NA {
   public:
    NA(A* a) : a_(a) {}
    void do_abc() { a_->do_xy(); }

   private:
    A* a_;
  };

  A(T1 t1, T2 t2) : t1_(t1), t2_(t2) {
    auto na = new NA(this);
    b_ = new B<NA>(na);
  }

  void do_this() { b_->do_that(); }
  void do_xy() { t1_.do_x(); t2_.do_y(); }

 private:
  T1 t1_;
  T2 t2_;
  B<NA>* b_;
};

简而言之:A 取决于 T1T2BB 依赖于 NA 嵌套在 A 中,NA 又依赖于 A.

我想使 B<NA> 成为 class A 的模板参数,并将 some b 传递给 A's constructor(就像 T1T2).

我首先尝试将 NA 移动到 A 之外并制作 BNA 模板参数 A 但它没有工作 NA 取决于 A(通过 A* a_;a_->do_xy();)。

我应该去做什么?

从技术上讲,您可以制作 NA 模板:

template <class T>
class NA {
public:
    NA(T* a) : a_(a) {}
    void do_abc() { a_->do_xy(); }

private:
    T* a_;
};

然而,问题是它是否能正确表达您的设计意图。

NA 依赖于 A 没有理由不在 A 之外声明它。只需向前声明 Aclass A;。它是一个不完整的类型,但是有一个指针是没有问题的。你只需要在 A 的实际定义之后再定义 do_abc()。但是在那之前有声明是没有问题的。编辑:这当然会使 NA 也明确地(它已经隐含地)依赖于 T1T2,所以你必须将它用作 NA<T1, T2> in A.

当然,您也可以使用 template template parameters 和模板 A 以及 template< class T1, class T2, template<class> class B1, class NA1>(对不起,奇怪的名字,但它们不应该隐藏 类) .

使用模板模板参数和工厂,您可以这样做:

template <typename T1, typename T2, template <typename> class C = B>
class A {
public:
   class NA
   {
   public:
       NA(A* a) : a_(a) {}
       void do_abc() { a_->do_xy(); }

   private:
       A* a_;
   };

   template <typename Factory> // or possibly std::function<C<NA>*(A*)>
   A(T1 t1, T2 t2, Factory f) : t1_(t1), t2_(t2), b_(f(this)) {}

  void do_this() { b_->do_that(); }
  void do_xy() { t1_.do_x(); t2_.do_y(); }

 private:
    T1 t1_;
    T2 t2_;
    C<NA>* b_;
};

使用情况:

auto b_factory = [](A<MyType1, MyType2>* a){
        auto* na = new A<MyType1, MyType2>::NA(a);
        return new B<A<MyType1, MyType2>::Na>(na);
    };
MyType1 t1{/*...*/};
MyType2 t2{/*...*/};

A<MyType1, MyType2, B> a(t1, t2, b_factory)