C++ 如何提高此模式所需的模板递归深度?
在我的代码中,我一直在使用这个SO问题中描述的模式来创建各种编译时注册列表: 例如,如果您有一组lua回调函数,并且您不想忘记将它们注册到某个lua状态,那么您可以使用一个宏来声明它们,该宏将知道它们的名称和函数指针的模板类型放入一个列表中,然后您将有一个一行程序来注册所有函数 此技术的一个限制(如SO答案中所述)是,如果列表中有C++ 如何提高此模式所需的模板递归深度?,c++,templates,c++11,recursion,c++14,C++,Templates,C++11,Recursion,C++14,在我的代码中,我一直在使用这个SO问题中描述的模式来创建各种编译时注册列表: 例如,如果您有一组lua回调函数,并且您不想忘记将它们注册到某个lua状态,那么您可以使用一个宏来声明它们,该宏将知道它们的名称和函数指针的模板类型放入一个列表中,然后您将有一个一行程序来注册所有函数 此技术的一个限制(如SO答案中所述)是,如果列表中有n项,则需要模板递归深度O(n)进行评估。这并不理想,实际上我已经有很多lua回调函数了 我曾认为,由于各种原因,O(n)递归深度是不可避免的,然而,正如我最近在这个(
n
项,则需要模板递归深度O(n)
进行评估。这并不理想,实际上我已经有很多lua回调函数了
我曾认为,由于各种原因,O(n)
递归深度是不可避免的,然而,正如我最近在这个(未解释的)答案中从雅克那里学到的,我天真地认为需要O(n)
的一些基本事情实际上可以在O(logn)
深度中完成
特别是,不再有任何理由认为所涉及的数据结构需要O(logn)
模板深度来进行操作
我不确定的部分是Rank
技巧。根据引用的代码,此模板
template <int N>
struct Rank : Rank<N - 1> {};
template <>
struct Rank<0> {};
然后,在代码中的任何一点,decltype(f(Rank{}))
的type都等于最近定义的重载的返回值。也就是说,这些断言是通过的
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:");
boolf(Rank){返回false;}
静态断言(std::is_same::value,“D:”);
int f(秩){返回0;}
静态断言(std::is_same::value,“D:”);
浮点f(秩){返回0;}
静态断言(std::is_same::value,“D:”);
双f(秩){返回0;}
静态断言(std::is_same::value,“D:”);
有没有一种方法不需要模板递归深度O(n)
也许可以为函数重载(?)使用更多仔细选择的参数,以避免类型错误: 模板实例化深度超过最大值900(使用-ftemplate depth=增加最大值)实例化“struct Rank” 在不增加全局最大模板深度的情况下,您可以实例化中间模板:
// 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>;
//允许模板深度为256的列组实例化
模板结构等级;
模板结构等级;
模板结构等级;
模板结构等级;
您还可能有一个助手:
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>
{};
名称空间详细信息
{
模板
结构实例化_Impl;
模板
结构实例化\u Impl
{
std::元组虚拟;
};
}
模板
结构实例化:
细节::实例化_Impl
{};
然后
template struct Instantiate<Rank, 2000, 250>; // Rank<2000> is now instantiated.
模板结构实例化;//等级现在被实例化。
您是否测量了所采取的措施?作为总时间的一部分,它对你有意义吗?或者这是出于“学术”的兴趣?@TonyD:我不太关心时间,我只关心达到最大模板递归深度(通常为256)并消除编译过程错误。我在一些地方使用这种模式——如果限制非常大,比如说,以百万计,而不是以数百计,那就太好了,所以我不必跟踪这些东西。在“学术”兴趣之外,获得它比获得O(logn)
更重要。这项工作的关键是Rank
是所有M的Rank
的直接或间接基类。您不能真正避免线性实例化。@ChrisBeck我提到运行时性能,因为您表面上是在使用编译时技术,而不是让宏使用注册单个函数的构造函数创建静态对象,或将名称和函数指针添加到标准库容器,以进行post-main()
注册。您正在调用哪种注册函数可以更好地处理编译时(函数指针)类型信息?也许如果我们能看到您最终拨打的lua注册码,我们会感激/评估您的需求或好处。。。。
template struct Instantiate<Rank, 2000, 250>; // Rank<2000> is now instantiated.