Как понять синтаксис туберкулезаи как этот код работает, чтобы избежать бесконечной рекурсии? - PullRequest
0 голосов
/ 14 декабря 2018

Я получил пример кода, как показано ниже:

#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();
}

Это понимание этого ответа , этот код гарантирует, что класс B имеет члена A1 иA1 имеет ссылку B.

Хотя этот код работает, я действительно не знаю, как он работает, особенно код const TB<A1<TB>> &b_;.Поскольку TB является параметром шаблона шаблона, TB<...> является специализацией TB, какой параметр A1<TB>, верно?Тогда что означает второй TB в TB<A1<TB>>?Если второй TB является шаблоном, почему нет параметра?

Как уже упоминал Матье Брухер, этот код действительно используется, чтобы избежать бесконечной рекурсии.Поскольку я не до конца понимаю, как работает этот код, может ли кто-нибудь объяснить, как компилятор работает, чтобы этот код работал?Или как должен выглядеть этот код после компиляции?

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

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>).
0 голосов
/ 14 декабря 2018

По вдохновению Матье Брухера и 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_;
};

шаблона больше нет.

0 голосов
/ 14 декабря 2018

Второй 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...