Может ли кто-нибудь объяснить, как создается экземпляр следующего базового шаблона и специализации для получения правильного результата? Мне особенно неясно, как интерпретируется параметр шаблона <U[N]>
. Это потому, что параметр шаблона, не относящийся к типу, рекурсивно ссылается на последнее/внешнее измерение?
Я видел этот вопрос, связанный с шаблонами, на который мне указали как на похожий, но он не касается метафункций шаблонов, многомерных массивов или рекурсии.
//The primary template handles scalar (non-array) types as a base case
template <class T>
struct rank { static size_t const value = 0U; };
//The partial specialization recognizes an array type:
template <class U, size_t N>
struct rank<U[N]> {
static size_t const value = 1u + rank<U>::value;
};
int main() {
using array_t = int[10][20][30];
//yields 3u (at compile time)
std::cout << "rank is " << rank<array_t>::value << std::endl;
}
Этот код взят из этого видео на YouTube о метапрограммировании шаблонов.
он рекурсивно создает экземпляр специализированного шаблона, отслаивая по одному экстенту за раз, пока он не перестанет быть массивом и первичный шаблон не даст значение 0.
«Этот код взят из этого видео на YouTube…» Я бы рекомендовал для этого использовать cppinsights . Также книга по C++ . И Можем ли мы увидеть шаблоны, созданные компилятором C++? где в этом ответе упоминается cppinsight.
Они создаются:
struct rank<int> { static size_t const value = 0U; };
struct rank<int[10]> {
static size_t const value = 1u + rank<int>::value;
};
struct rank<int[10][20]> {
static size_t const value = 1u + rank<int[10]>::value;
};
struct rank<int[10][20][30]> {
static size_t const value = 1u + rank<int[10][20]>::value;
};
int main() {
using array_t = int[10][20][30];
//yields 3u (at compile time)
std::cout << "rank is " << rank<array_t>::value << std::endl;
}
Спасибо. Это очень наглядно помогает понять, что делает компилятор. Я предполагаю, что часть моего недоразумения была связана с тем, как C++ преобразует аргумент шаблона, не относящийся к типу, в массив с меньшим количеством измерений на каждой итерации. (Мне также напомнили попробовать cppinsights для... понимания.)
Для типа
int[10][20][30]
U
становитсяint[10][20]
, аN
становится последним30
. Для следующей «рекурсии»U
— этоint[10]
, аN
— это20
. ТогдаU
— этоint
, который использует базовую структуру для «возврата»0
. Итак, по сути, у вас естьrank<int[10][20][30]>::value
(из функцииmain
,rank<int[10][20]>::value
,rank<int[10]>::value
и, наконец,rank<int>::value
.