我一直在我的代码中使用这个 SO 问题中描述的模式来制作各种编译时注册列表:C++ type registration at compile time trick
例如,如果你有一堆 lua 回调函数并且你不想忘记将它们注册到某个 lua 状态,你可以使用一个宏来声明它们,该宏将知道它们的名称和函数指针的模板类型放入一个列表,然后你有一个单行代码,它注册了所有的功能。
此技术的局限性(如 SO 答案中所述)是,如果您有 n
列表中的项目,它需要模板递归深度O(n)
评估。这并不理想,实际上我已经有不少 lua 回调函数了......
我曾相信O(n)
由于各种原因,递归深度是不可避免的,但是正如我最近在这个(未发布的)答案中从 Yakk 那里了解到的,我天真地认为需要一些基本的东西 O(n)
实际上可以在 O(log n)
中完成深度。 Switch statement variadic template expansion
特别是没有理由再要求所涉及的数据结构需要 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>{}))
具有等于最近定义的重载的返回值的类型。 IE。这些断言通过
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)
?
也许为函数重载使用更多、精心选择的参数(?)
最佳答案
为了避免类型错误:
template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating '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>;
你可能还有一个 helper :
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.
关于c++ - 如何提高该模式所需的模板递归深度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32241555/