c++ - 如何提高该模式所需的模板递归深度?

标签 c++ templates c++11 recursion c++14

我一直在我的代码中使用这个 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/

相关文章:

c++ - 无法初始化指向具有基类右值的子类的指针

c++ - 类方法的结果类型?

c++ - 比较两组类型是否相等

c++ - 单一类型编译时间列表 : concat with clang

c++ - std::hash 特化仍未被 std::unordered_map 使用

html - 展望负表 margin

c++ - std::is_nothrow_move_constructible 是否需要 noexcept 析构函数?

c++ - 有-O2 和没有-O2 的成员变量的不同行为

c++ - VS2015 C++协程: promise. get_return_object()返回类型和协程返回类型

c++ - 如何在 OpenCV 中获取特定元素的行和列?