Search code examples
c++templatesusing

C++: recursive dependency in type alias


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;
}

Solution

  • 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).