Здесь нет рекурсии. Ваш класс tmp::ShowValueClass<T>
работает только для любого типа T
, имеющего член value
, который может быть напечатан на cout
(имеет право ostream& operator<<(ostream&, const T&)
определено).
Тот факт, что вы добавили псевдоним типа ShowValueClass
внутри ValueClass
со ссылкой на tmp::ShowValueClass<ValueClass>
, ничего не изменило. В этом контексте класс действует как пространство имен.
Подумайте, что случится, если вы извлечете ShowValueClass
из ValueClass
:
struct ValueClass {
static constexpr int value = 42;
};
using ShowValueClass = tmp::ShowValueClass<ValueClass>;
В этом случае вы бы получили доступ к ShowValueClass
непосредственно в main()
вместо префикса с ValueClass::
, как в вашем случае. Факты, которые tmp::ShowValueClass
использует T::value
и что псевдоним типа ShowValueClass
находится в ValueClass
, не имеют значения (в них нет ничего особенного).
Вся идея использования самого класса в качестве параметра шаблона класса шаблона широко распространена в C ++. На самом деле, существует шаблон с именем CRTP (Curily Recurring Template Pattern), в котором класс наследуется от класса шаблона с использованием в качестве параметра самого класса (из Википедии):
// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
Вы можете проверить всю статью здесь: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Пример истинной рекурсивной зависимости
Теперь, чтобы завершить картину, я могу показать вам код, который не скомпилирует из-за рекурсивного определения:
template <typename T>
struct A {
static constexpr int val = T::val;
};
struct B {
static constexpr int val = A<B>::val;
};
int main() { }
Здесь A<T>::val
зависит от T::val
, и это нормально, но B::val
зависит от A<B>::val
, который расширяется до B::val
. Другими словами, B::val
зависит от B::val
, что явно не может быть разрешено . Это как сказать, что:
x := y(x)
с y(x)
:
y(x) := x.
Следовательно, x := x
. Ясно, что нет способа определить значение для x
.
Рабочий пример использования рекурсии шаблона
Теперь, если рекурсия выполнена правильно и определен базовый случай , ясно, что его можно использовать даже для вычисления довольно сложных вещей.
Вот тривиальный пример:
#include <iostream>
using namespace std;
template <int N>
struct A {
static constexpr int val = N + A<N - 1>::val;
};
template <>
struct A<0> {
static constexpr int val = 0;
};
int main() {
cout << A<10>::val << endl;
}
A<N>::val
определяется рекурсивно как:
N + A<N-1>::val if N != 0
0 if N == 0
И, как результат, это сумма всех чисел от 0
до N
(включительно).