2

I am wondering whether the following code is correct. It compiles and runs on my computer but I feel like there is a recursive dependency of ShowValueClass type alias defined in ValueClass. Could you please explain how the compiler was able to resolve it?

#include <iostream>

namespace tmp {
template <typename T>
struct ShowValueClass {
  void ShowValue() { std::cout << T::value << std::endl; }
};
} // namespace tmp

struct ValueClass {
  using ShowValueClass = tmp::ShowValueClass<ValueClass>;
  static constexpr int value = 42;
};

int main() {
  ValueClass::ShowValueClass s;
  s.ShowValue();
  return 0;
}
TruLa
  • 1,031
  • 11
  • 21

1 Answers1

2

There is no recursion here. Your class tmp::ShowValueClass<T> just works for any type T having a member value that is printable by cout (has the right ostream& operator<<(ostream&, const T&) defined).

The fact that you added a type alias called ShowValueClass inside ValueClass referring to tmp::ShowValueClass<ValueClass> changed nothing. In that context, the class acts just like a namespace.

Think about what would happen if you extracted ShowValueClass from ValueClass:

struct ValueClass {
  static constexpr int value = 42;
};

using ShowValueClass = tmp::ShowValueClass<ValueClass>;

In that case you would accessed ShowValueClass directly in main() instead of prefixing it with ValueClass::, as in your case. Both the facts that tmp::ShowValueClass uses T::value and that the type alias ShowValueClass is in ValueClass are irrelevant (there's nothing special about them).

The whole idea of using a class itself as a template parameter of a template class is widespread in C++. Actually, there is pattern called CRTP (Curiously Recurring Template Pattern) where a class inherits from template class using as parameter the class itself like (from Wikipedia):


// 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>
{
    // ...
};

You can check the whole article here: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

A true recursive dependency example

Now, just to complete the picture, I can show you some code that won't compile because of a recursive definition:

template <typename T>
struct A {
   static constexpr int val = T::val;
};

struct B {
   static constexpr int val = A<B>::val;
};

int main() { }

Here, A<T>::val depends on T::val and that's OK, but B::val depends on A<B>::val which expands to B::val. In order words, B::val depends on B::val, which clearly cannot be resolved. It's like saying that:

x := y(x)

with y(x) being:

y(x) := x. 

Therefore, x := x. Clearly, there is no way to determine a value for x.

A working example using template recursion

Now, if the recursion is properly made and there is a base case defined, clearly it can be used even to compute pretty complex things. Here's a trivial example:

#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 is defined recursively as:

N + A<N-1>::val if N != 0
0               if N == 0

And, as a result, it is the sum of all the numbers from 0 to N (inclusive).

vvaltchev
  • 609
  • 3
  • 20
  • Thank you so much. No only I found an answer to my question but also learned a new concept. It's so exciting! – TruLa Jan 18 '19 at 09:01