如何改进此模式所需的模板递归深度
How to improve the template recursion depth required for this pattern?
我一直在我的代码中使用这个问题中描述的模式来制作各种编译时注册列表:c++类型在编译时注册技巧
例如,如果你有一堆lua回调函数,你不想忘记用一些lua状态注册它们,你可以使用一个宏来声明它们,该宏将模板类型放入一个列表中,该列表知道它们的名称和函数指针,然后你有一个一行代码来注册所有的函数。
该技术的一个限制(如SO答案中所述)是,如果列表中有n
项,则需要模板递归深度O(n)
来求值。这是不理想的,我实际上有相当多的lua回调函数已经…
我曾经认为O(n)
递归深度由于各种原因是不可避免的,然而,正如我最近从Yakk那里了解到的,一些我天真地认为需要O(n)
的基本事情实际上可以在O(log n)
深度中完成。Switch语句可变模板扩展
特别是,所涉及的数据结构不再需要O(log n)
模板深度来进行操作。
我不确定的部分是Rank
技巧。从引用的代码中,这个模板
template <int N>
struct Rank : Rank<N - 1> {};
template <>
struct Rank<0> {};
是一个关键因素。但是,它在模板深度方面是昂贵的——实例化Rank<N>
需要模板深度N
。它具有的重要属性是,如果定义了一个函数f
,它使用许多不同的秩类型重载,重载解析总是选择最大秩的重载,因为这是"最派生的实例"。例如,如果我们有这样的代码:
bool f(Rank<0>) { return false; }
int f(Rank<1>) { return 0; }
float f(Rank<2>) { return 0; }
double f(Rank<3>) { return 0; }
则总是在代码中的任何一点,decltype(f(Rank<100>{}))
的类型等于最近定义的重载的返回值。例如,这些断言传递
bool f(Rank<0>) { return false; }
static_assert(std::is_same<bool, decltype(f(Rank<100>{}))>::value, "D:");
int f(Rank<1>) { return 0; }
static_assert(std::is_same<int, decltype(f(Rank<100>{}))>::value, "D:");
float f(Rank<2>) { return 0; }
static_assert(std::is_same<float, decltype(f(Rank<100>{}))>::value, "D:");
double f(Rank<3>) { return 0; }
static_assert(std::is_same<double, decltype(f(Rank<100>{}))>::value, "D:");
是否有一种方法可以做到这一点,而不需要模板递归深度O(n)
?
可以为函数重载(?)使用更多精心选择的参数
避免出现以下错误:
模板实例化深度超过900的最大值(使用-ftemplate-depth=增加最大值)实例化'struct Rank<1148u>'
不增加全局最大模板深度,您可以实例化中间模板:
// To allow instantiation of Rank<1000> with template-depth at 256
template struct Rank<250>;
template struct Rank<500>;
template struct Rank<750>;
template struct Rank<1000>;
你也可以有一个帮手:
namespace detail
{
template <template <std::size_t> class C,
typename Seq,
std::size_t BlockSize>
struct Instantiate_Impl;
template <template <std::size_t> class C,
std::size_t... Is,
std::size_t BlockSize>
struct Instantiate_Impl<C, std::index_sequence<Is...>, BlockSize>
{
std::tuple<C<(Is * BlockSize)>...> dummy;
};
}
template <template <std::size_t> class C,
std::size_t N,
std::size_t BlockSize = 250>
struct Instantiate :
detail::Instantiate_Impl<C,
std::make_index_sequence<1 + N / BlockSize>,
BlockSize>
{};
和
template struct Instantiate<Rank, 2000, 250>; // Rank<2000> is now instantiated.
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 使用后序遍历递归的深度优先搜索会产生意外输出
- 由于深度递归而导致堆栈溢出
- 5000+ 深度递归时函数堆栈溢出
- OpenMP:即使在深度极限的情况下,递归任务也比顺序慢
- 可变参数模板实例化中的无限递归,试图构建任意深度的树状结构
- lambda 的深度递归
- C++递归函数,调用当前深度
- 递归的最大深度是多少?
- 查找最大递归深度
- 如何跳出一些深度递归的函数并直接返回结果
- 如何跟踪递归深度
- 如何改进此模式所需的模板递归深度
- 递归深度切断策略:并行快速排序
- 具有合成和继承属性的深度递归qi语法(解析器)
- 为什么这超过了递归模板的最大深度
- 递归模板实例化超出了最大深度 256
- 深度优先搜索或回溯递归查找字谜/拼字板中所有可能的字母组合