Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does int*** in this template metaprogram work?

How is template metaprogramming working here (static const int value = 1 + StarCounter<\U>::value;) to print out 3 ?

#include <iostream>

template <typename T>
struct StarCounter
{
    static const int value = 0;
};

template <typename U>
struct StarCounter<U*>
{
    static const int value = 1 + StarCounter<U>::value;
};

int main()
{
    std::cout << StarCounter<int***>::value << std::endl;//How is it printing 3?
    return 0;
}
like image 604
Abhijith Avatar asked Dec 18 '16 07:12

Abhijith


People also ask

How does template metaprogramming work?

Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled.

Why use template metaprogramming?

You must use template metaprogramming to achieve what would have been easy and straightforward C++, and this always happens when the users of C++ aren't careful enough not to move too many things to compile-time.

What is TMP in C++?

Template meta-programming (TMP) refers to uses of the C++ template system to perform computation at compile-time within the code. It can, for the most part, be considered to be "programming with types" — in that, largely, the "values" that TMP works with are specific C++ types.

What is templating in programming?

A template is a C++ programming feature that permits function and class operations with generic types, which allows functionality with different data types without rewriting entire code blocks for each type.


2 Answers

The first template creates a struct that will always return 0 when you call StarCounter<U>::value.

The second template specialises the first one for cases where a pointer is used. So when you call it with StarCounter<U*>::value, the second template is used, not the first and it will return StarCounter<U>::value + 1. Note that it removes the pointer at each recursion step.

So the call to StarCounter<int***>::value will expend to:

StarCounter<int***>::value // second template is used due to pointer
1 + StarCounter<int**>::value // second template is used due to pointer
1 + 1 + StarCounter<int*>::value // second template is used due to pointer
1 + 1 + 1 + StarCounter<int>::value // no pointer here, so first template is used
1 + 1 + 1 + 0
3
like image 163
Grumbel Avatar answered Sep 27 '22 16:09

Grumbel


StarCounter<int>::value

equals 0, because it's matched with first instantiation of the template, where value is explicitly defined.

StarCounter<int*>::value = 1 + StarCounter<int>::value

equals 1, because StarCounter<int*> is matched with StarCounter<U*>. Yes, StarCounter<T> can also be considered as a match, but StarCounter<U*> is more specific and that's why this one is preferred.

Similarly,

StarCounter<int**>::value = 1 + StarCounter<int*>::value

equals 2 and

StarCounter<int***>::value = 1 + StarCounter<int**>::value

equals 3.

like image 36
alexeykuzmin0 Avatar answered Sep 27 '22 16:09

alexeykuzmin0