我得到了如下示例代码:
#include <iostream>
template<class T1>
class B {
public:
B() : t1_(*this) {}
void Test() {
t1_.Test();
}
void Print() const {
std::cout << "test\n";
}
private:
T1 t1_;
};
template<template<class> class TB>
class A1 {
public:
explicit A1(const TB<A1<TB>> &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const TB<A1<TB>> &b_;
};
int main() {
B<A1<B>> bt;
bt.Test();
}
这是answer的见识,此代码确保类B
具有成员A1
,并且A1
具有引用B
。
尽管此代码有效,但我真的不知道它如何工作,尤其是代码const TB<A1<TB>> &b_;
。由于TB
是模板模板参数,因此TB<...>
是TB
的特化,哪个参数是A1<TB>
,对吧?那么TB
中第二个TB<A1<TB>>
是什么意思?如果第二个TB
是模板,为什么没有参数?
正如Matthieu Brucher所提到的,该代码确实用于避免无限递归。由于我不完全了解此代码的工作原理,因此任何人都可以解释编译器如何使此代码工作吗?或者,该代码在编译后应该是什么样?
答案 0 :(得分:4)
由于TB
的声明,第二个A1
没有参数:
template<template<class> class TB>
class A1;
这表示A1
接受一个模板参数,而参数本身接受未指定的模板参数。 A1
可以使用此模板参数做任何需要的事情,但是在声明A1
时一定不要给它,这会破坏没有此功能时发生的无限递归。
例如,您可以编写:
A1<TB> foo;
您也可以写:
A1<std::vector> foo(std::vector<A1<std::vector>>()); // UB because of b storage, but it's the example
答案 1 :(得分:3)
B
需要一个类型,而A1
需要一个模板。
因此您可能有B<int>
,但没有A1<int>
。
同样,您可能有A1<B>
,但没有B<B>
。
返回
template<template <class > class TB> class A1;
TB
是模板,而不是类型,但是TB<int>
是类型。
所以TB<A1<TB>>
,
TB
是模板。A1<TB>
是一种类型。TB< T2 >
是一种类型(T2
= A1<TB>
)。答案 2 :(得分:0)
受Matthieu Brucher和Jarod42的启发,我将尝试使用编译器的视图进行解释,如果我错了,请纠正我。
如Jarod42所述:
(内部)TB是模板。
A1
是一种类型。 TB
是一种类型(T2 = A1)
并且由于模板将在使用时实例化,因此B<A1<B>> bt;
行是模板属于某种类型的位置。
因此,A1<B>
是一个类型,让我们将真实的类命名为A1_IMPL,即A1<B>--A1_IMPL
,B<A1<B>>
是一个类型,将其命名为B_IMPL的类,即B<A1<B>>--B<A1_IMPL>--B_IMPL
。因此,B_IMPL如下所示:
class B_IMPL {
public:
B_IMPL() : t1_(*this) {}
void Test() {
t1_.Test();
}
void Print() const {
std::cout << "test\n";
}
private:
A1_IMPL t1_;
};
A1看起来像这样:
class A1_IMPL {
public:
explicit A1_IMPL(const B<A1<B>> &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const B<A1<B>> &b_;
};
尚未完成,因为A1<B>--A1_IMPL
,B<A1<B>>--B<A1_IMPL>--B_IMPL
,最终的A1_IMPL如下所示:
class A1_IMPL {
public:
explicit A1_IMPL(const B_IMPL &b) : b_(b) {}
void Test() {
b_.Print();
}
private:
const B_IMPL &b_;
};
没有模板了。