[英]Recursive template type declaration
我正在尝试创建一个包含 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>
。 任何帮助,将不胜感激。 谢谢!
为后代编辑:
这个问题有很多错误。 正如@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 中,您有编译时 integer 下溢,因为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
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.