重构模板 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
取决于 T1
、T2
和 B
。 B
依赖于 NA
嵌套在 A
中,NA
又依赖于 A
.
我想使 B<NA>
成为 class A
的模板参数,并将 some b
传递给 A's constructor
(就像 T1
和 T2
).
我首先尝试将 NA
移动到 A
之外并制作 B
和 NA
模板参数 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
之外声明它。只需向前声明 A
和 class A;
。它是一个不完整的类型,但是有一个指针是没有问题的。你只需要在 A
的实际定义之后再定义 do_abc()
。但是在那之前有声明是没有问题的。编辑:这当然会使 NA
也明确地(它已经隐含地)依赖于 T1
和 T2
,所以你必须将它用作 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)
在重构代码以便于对现有代码库进行单元测试时,我发现了一个如下所示的代码片段:
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
取决于 T1
、T2
和 B
。 B
依赖于 NA
嵌套在 A
中,NA
又依赖于 A
.
我想使 B<NA>
成为 class A
的模板参数,并将 some b
传递给 A's constructor
(就像 T1
和 T2
).
我首先尝试将 NA
移动到 A
之外并制作 B
和 NA
模板参数 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
之外声明它。只需向前声明 A
和 class A;
。它是一个不完整的类型,但是有一个指针是没有问题的。你只需要在 A
的实际定义之后再定义 do_abc()
。但是在那之前有声明是没有问题的。编辑:这当然会使 NA
也明确地(它已经隐含地)依赖于 T1
和 T2
,所以你必须将它用作 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)