如何理解语法TB <a1 <tb >>以及此代码如何工作以防止无限递归?

时间:2018-12-14 09:29:38

标签: c++ templates

我得到了如下示例代码:

#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所提到的,该代码确实用于避免无限递归。由于我不完全了解此代码的工作原理,因此任何人都可以解释编译器如何使此代码工作吗?或者,该代码在编译后应该是什么样?

3 个答案:

答案 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_IMPLB<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_IMPLB<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_;
};

没有模板了。