我正在尝试创建一个包含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
完全展开了这两个选项但当我尝试接近B时,我会出现以下错误:
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;
将设置CCD_ 9。如有任何帮助,我们将不胜感激。非常感谢。
为子孙后代编辑:
这个问题没有错。正如@cdhowie指出的那样,我没有正确遵循指南。以下是一个行之有效的解决方案:
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;
};
在方法A中,由于两个";分支";即使条件选择了另一个std::conditional
。因此,type_helper
会导致尝试实例化的无限递归。
方法B的编译错误是您的专门化语法错误。此:
template<typename T, uint32_t nlevels, uint32_t level, uint32_t other_nvecs>
struct type_helper {
using type = slab<T, nvecs>;
};
应该是这样的:
template<typename T, uint32_t nlevels, uint32_t level, uint32_t other_nvecs>
struct type_helper<T, nlevels, level, other_nvecs> {
using type = slab<T, nvecs>;
};
方法B陷入了与方法A完全相同的无限递归问题:type_helper<T, nlevels, level, other_nvecs...>
将始终实例化type_helper<T, nlevels, level - 1, other_nvecs...>
。level
下溢,并且递归继续,直到编译器放弃为止。
在这种情况下,终止递归的方法是在level
为零时定义一个特殊情况:
template<typename T, uint32_t nlevels, uint32_t... other_nvecs>
struct type_helper<T, nlevels, 0, other_nvecs...> {
using type = // whatever makes sense in your case
};
我不知道type
应该在这里是什么(但我想你知道(。
您还可以有一个最后的终止情况,其中level
为零,other_nvecs
为空:
template<typename T, uint32_t nlevels>
struct type_helper<T, nlevels, 0> {
using type = // something
};