I found and was debugging the code to find rank of an array - example float[4] array has rank 1. Similarly float[3][2] has rank 2 - where rank means the dimension of an array.
Below is the code using cppinsights:
#include <iostream>
template<typename T>
struct Rank
{
inline static constexpr const size_t value = 0;
};
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[1]>::value;
};
#endif
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[1]>
{
inline static constexpr const size_t value = 1U + Rank<float>::value;
};
#endif
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float>
{
inline static constexpr const size_t value = 0;
};
#endif
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
#endif
template<typename T, size_t N>
struct Rank<T[N]>
{
inline static constexpr const size_t value = 1U + Rank<T>::value;
};
int main()
{
/* PASSED: static_assert(Rank<float[3][2][1]>::value == 3); */
return 0;
}
The code works fine but I am not able to understand how compiler transforms "Rank<float[3][2][1]>" to "Rank<float[2][1]>" and N as 3 as in below code
template<>
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
To me it seems more like string regular expression what's the template signature is doing - the initial declaration was:
template <typename T, size_t N>
struct Rank<T[N]>
{
static constexpr size_t value = 1U + Rank<T>::value;
};
So this is a template partial specialization and a instantiation of template like Rank<float[3][2][1]> gets mapped to instantiation like:
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
But how does compiler promotes float[3][2][1] to Rank<float[2][1]> and deduces N as 3 - is it just like template declaration - Rank<T[N]> so Rank<float[3][2][1]> becomes line Rank<float[N][2][1]> - hence N becomes 3 and all other part is T?
I found and was debugging the code to find rank of an array - example float[4] array has rank 1. Similarly float[3][2] has rank 2 - where rank means the dimension of an array.
Below is the code using cppinsights:
#include <iostream>
template<typename T>
struct Rank
{
inline static constexpr const size_t value = 0;
};
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[1]>::value;
};
#endif
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[1]>
{
inline static constexpr const size_t value = 1U + Rank<float>::value;
};
#endif
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float>
{
inline static constexpr const size_t value = 0;
};
#endif
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
#endif
template<typename T, size_t N>
struct Rank<T[N]>
{
inline static constexpr const size_t value = 1U + Rank<T>::value;
};
int main()
{
/* PASSED: static_assert(Rank<float[3][2][1]>::value == 3); */
return 0;
}
The code works fine but I am not able to understand how compiler transforms "Rank<float[3][2][1]>" to "Rank<float[2][1]>" and N as 3 as in below code
template<>
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
To me it seems more like string regular expression what's the template signature is doing - the initial declaration was:
template <typename T, size_t N>
struct Rank<T[N]>
{
static constexpr size_t value = 1U + Rank<T>::value;
};
So this is a template partial specialization and a instantiation of template like Rank<float[3][2][1]> gets mapped to instantiation like:
struct Rank<float[3][2][1]>
{
inline static constexpr const size_t value = 1U + Rank<float[2][1]>::value;
};
But how does compiler promotes float[3][2][1] to Rank<float[2][1]> and deduces N as 3 - is it just like template declaration - Rank<T[N]> so Rank<float[3][2][1]> becomes line Rank<float[N][2][1]> - hence N becomes 3 and all other part is T?
Share Improve this question edited Mar 16 at 1:53 Programmer asked Mar 16 at 1:41 ProgrammerProgrammer 8,78924 gold badges93 silver badges180 bronze badges 5 |3 Answers
Reset to default 5Given:
template <typename T> // primary
struct Rank {
static constexpr size_t value = 0;
};
template <typename T, size_t N> // specialization
struct Rank<T[N]> {
static constexpr size_t value = 1U + Rank<T>::value;
};
Then value
is calculated by adding 1
for each match of the specialization:
Rank<float[3][2][1]>
matches the specialization in which T
is float[2][1]
and N
is 3
.
Rank<float[2][1]>
matches the specialization in which T
is float[1]
and N
is 2
.
Rank<float[1]>
matches the specialization in which T
is float
and N
is 1
.
Rank<float>
matches the primary.
You seem to be confused by the multidimensional array syntax. The syntax chosen to declare an array is not relevant, so there are no "string regular expression" as you say.
The declaration of the primary template is
template<typename T>
struct Rank
{
inline static constexpr const size_t value = 0;
};
and the specialization says
template <typename T, size_t N>
struct Rank<T[N]>
{
static constexpr size_t value = 1U + Rank<T>::value;
};
The specialization is used whenever the template parameter is an array of size N
. It doesn't matter what T
is. That T
is another array type does not change anything in deduction.
When passed the type float[3][2][1]
, the compiler sees it as an array of 3 elements, each is a float[2][1]
. It doesn't matter what syntax C++ chooses to express such a type. What matters is how the compiler sees it. This happens the moment the compiler parses the type expression, not later when the specialization is checked against.
You may find it easier to understand if the specialization is for std::array<T, N>
and the passed type is std::array<std::array<std::array<float, 1>, 2>, 3>
. However in the eye of the compiler these two are equally easy to deduce.
You should really ignore the specific syntax chosen to express a type (like the string "float[3][2][1]") as that is irrelevant to the internal representation of the compiler.
I don't think the recursion process is what OP is confused about so I'm not going to elaborate on that.
The recursive definition of Rank is:
Rank(N) = 0
Rank(T[Nn]...[N2][N1]) = 1 + Rank([Nn]...[N2])
In C++, this is
template<typename T>
struct Rank
{
inline static constexpr const size_t value = 0;
};
template<typename T, size_t N>
struct Rank<T[N]>
{
inline static constexpr const size_t value = 1U + Rank<T>::value;
};
- When you call
Rank<float[3][2][1]>
,T
getsfloat[2][1]
and the unusedN
gets 3.
So,Rank<float[3][2][1]>
calls1 + Rank<float[2][1]>
. - When it calls
Rank<float[2][1]>
,T
getsfloat[1]
and the unusedN
gets 2.
So,Rank<float[3][2][1]>
calls1 + 1 + Rank<float[1]>
. - When it calls
Rank<float[1]>
,T
getsfloat
and the unusedN
gets 1.
So,Rank<float[3][2][1]>
calls1 + 1 + 1 + Rank<float>
. - Finally, when it calls
Rank<float>
, it gets 0.
So,Rank<float[3][2][1]>
get1 + 1 + 1 + 0
that is 3.
float a[m][n];
thena[0]
isfloat(&)[n]
. This is likely used in a real code, a recursive template. – 3CxEZiVlQ Commented Mar 16 at 1:53float[3][2]
has rank 2 - where rank means the dimension of an array.” Well, no: the rank is 2, but this is not a dimension. The dimensions are 3 x 2. – Sergey A Kryukov Commented Mar 16 at 2:05