[英]How to improve the template recursion depth required for this pattern?
我一直在我的代碼中使用這個SO問題中描述的模式,制作各種編譯時注冊列表: 編譯時的C ++類型注冊技巧
例如,如果你有一堆lua回調函數並且你不想忘記用一些lua狀態注冊它們,你可以使用一個宏來聲明它們,這個宏將一個知道它們的名字和函數指針的模板類型放入一個列表中,然后你有一個記錄所有功能的單行程。
這種技術的局限性(如SO答案中所述)是,如果列表中有n
項目,則需要模板遞歸深度O(n)
進行評估。 這不太理想,我實際上已經有相當多的lua回調函數......
我曾經相信O(n)
遞歸深度由於各種原因是不可避免的,但是正如我最近從Yakk那里學到的(未經證實的)答案,我天真地認為需要的一些基本事物O(n)
實際上可以在O(log n)
完成O(log n)
深度。 切換語句可變參數模板擴展
特別是,所涉及的數據結構不再需要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.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.