Я пытаюсь создать структуру, которая содержит N вложенных шаблонных типов:
Код, который я должен сделать, это:
// slab (base case essentially)
template<typename T, uint32_t nvecs = 8, align_policy ap = align_policy::none>
struct slab {
T t;
};
// wrapper for either slab or other super_slabs
template<typename T,
uint32_t nvecs = 8,
uint32_t inner_nvec = 8,
typename inner_slab_t = slab<T, inner_nvec>>
struct super_slab {
inner_slab_t ist;
};
// hopefully correct functions to extract Nth values for argument pack
template<typename... Vals>
constexpr uint32_t
_get_0(uint32_t v, Vals... vals) {
return v;
}
template<typename... Vals>
constexpr uint32_t
_get_N(int32_t n, uint32_t v, Vals... vals) {
return n <= 0 ? _get_0(vals...) : _get_N(n - 1, vals...);
}
template<typename... Vals>
constexpr uint32_t
get_N(int32_t n, Vals... vals) {
return _get_N(n, vals...);
}
// first approach I tried
#ifdef APPROACH_A
template<typename T, uint32_t nlevels, uint32_t level, uint32_t... other_nvecs>
struct type_helper {
using type = typename std::conditional<
level <= 1,
slab<T, other_nvecs...>,
super_slab<T,
get_N(nlevels - level, other_nvecs...),
get_N(nlevels - (level + 1), other_nvecs...),
typename type_helper<T, nlevels, level - 1, other_nvecs...>::
type>>::type;
};
#endif
// second approach I tried
#ifdef APPROACH_B
template<typename T, uint32_t nlevels, uint32_t level, uint32_t... other_nvecs>
struct type_helper;
template<typename T, uint32_t nlevels, uint32_t level, uint32_t... other_nvecs>
struct type_helper {
using type = super_slab<
T,
get_N(nlevels - level, other_nvecs...),
get_N(nlevels - (level + 1), other_nvecs...),
typename type_helper<T, nlevels, level - 1, other_nvecs...>::type>;
};
template<typename T, uint32_t nlevels, uint32_t level, uint32_t other_nvecs>
struct type_helper {
using type = slab<T, nvecs>;
};
#endif
// struct I want to use for API.
template<typename T, uint32_t levels, uint32_t... level_nvecs>
struct slab_manager {
using slab_t =
typename type_helper<T, levels, levels, level_nvecs...>::type;
};
APPROACH_A компилируется, но когда я пытаюсь создать экземпляр это с:
slab_manager<uint64_t, 1, 8> m;
Я получаю сообщение об ошибке:
slab_manager.h: In instantiation of ‘struct type_helper<long unsigned int, 1, 4294966399, 8>’:
slab_manager.h:39:36: recursively required from ‘struct type_helper<long unsigned int, 1, 0, 8>’
slab_manager.h:39:36: required from ‘struct type_helper<long unsigned int, 1, 1, 8>’
slab_manager.h:63:70: required from ‘struct slab_manager<long unsigned int, 1, 8>’
obj_slab_test.cc:213:34: required from here
slab_manager.h:36:25: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
get_N(nlevels - level, other_nvecs...),
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Я действительно не понимаю, как ‘struct type_helper<long unsigned int, 1, 4294966399, 8>’:
когда-либо происходит, поскольку передача 1
- начальный уровень должен вызывать это просто поразить базовый регистр в std::conditional
. Я предполагал, что проблема заключалась в том, что std::conditional
полностью разворачивает оба варианта, но когда я пытаюсь приблизиться, BI получаю следующие ошибки:
slab_manager.h:43:68: error: template parameter ‘unsigned int ...other_nvecs’
template<typename T, uint32_t nlevels, uint32_t level, uint32_t... other_nvecs>
^~~~~~~~~~~
slab_manager.h:55:8: error: redeclared here as ‘unsigned int other_nvecs’
struct type_helper {
^~~~~~~~~~~
slab_manager.h: In instantiation of ‘struct type_helper<long unsigned int, 1, 4294966399, 8>’:
slab_manager.h:51:75: recursively required from ‘struct type_helper<long unsigned int, 1, 0, 8>’
slab_manager.h:51:75: required from ‘struct type_helper<long unsigned int, 1, 1, 8>’
slab_manager.h:63:70: required from ‘struct slab_manager<long unsigned int, 1, 8>’
obj_slab_test.cc:213:34: required from here
slab_manager.h:49:14: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
get_N(nlevels - level, other_nvecs...),
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Это означает, что причина сбоя A НЕ связана с std::conditional
, но меня смущает больше, потому что метод повторного объявления типов с базовым случаем был тем, что я видел в каждом руководстве, которое я видел до сих пор.
Я предполагаю, что вызов slab_manager<uint64_t, 1, 8> m;
установит slab_t = slab<uint64_t, 8>
и, например, slab_manager<uint64_t, 3, 2, 4, 8> m;
установит slab_t = super_slab<uint64_t, 2, 4, super_slab<uint64_t, 4, 8, slab<uint64_t, 8>
. Любая помощь будет оценена. Спасибо!
Редактировать для потомков:
В этом вопросе было ОЧЕНЬ НЕПРАВИЛЬНО. как заметил @ cdhow ie, я неправильно следовал руководствам. Вот решение, которое сработало:
template<typename... Vals>
constexpr int32_t
_get_0(int32_t v, Vals... vals) {
return v;
}
template<typename... Vals>
constexpr int32_t
_get_0(int32_t v) {
return v;
}
template<typename... Vals>
constexpr int32_t
_get_N(int32_t n, Vals... vals) {
return n <= 0 ? _get_0(vals...) : _get_N(n - 1, vals...);
}
template<typename... Vals>
constexpr int32_t
get_N(int32_t n, Vals... vals) {
return _get_N(n, vals...);
}
template<typename T, int32_t nlevels, int32_t level, int32_t... other_nvecs>
struct type_helper;
template<typename T, int32_t nlevel, int32_t... other_nvecs>
struct type_helper<T, nlevel, 0, other_nvecs...> {
typedef slab<T, get_N(nlevel, other_nvecs...)> type;
};
template<typename T, int32_t nlevels, int32_t level, int32_t... other_nvecs>
struct type_helper {
typedef super_slab<T,
get_N(nlevels - level, other_nvecs...),
get_N(nlevels - (level + 1), other_nvecs...),
typename type_helper<T, nlevels, level - 1, other_nvecs...>::type>
type;
};
template<typename T, int32_t levels, int32_t... level_nvecs>
struct slab_manager {
using slab_t = typename type_helper<T, levels, levels - 1, level_nvecs...>::type;
};