[英]How can I concisely write a lot of explicit function template instantiations?
[英]How can I instantiate template of multiple enums concisely?
如果我想為模板 function Caclculate
實例化 Type1、Type2 和 Type3 的所有組合,看來我必須編寫 72 行代碼。 有沒有辦法簡化這些代碼?
#include <iostream>
#include <map>
#include <tuple>
#include <functional>
enum Type1 {
kType1_1,
kType1_2,
kType1_3,
kType1_4,
kType1_5,
kType1_6,
};
enum Type2 {
kType2_1,
kType2_2,
kType2_3,
};
enum Type3 {
kType3_1,
kType3_2,
kType3_3,
kType3_4,
};
template <Type1 t1, Type2 t2, Type3 t3>
int Caclculate() {
std::cout << static_cast<int32_t>(t1) << " " << static_cast<int32_t>(t2) << std::endl;
return 0;
}
int CalculateHandler(Type1 t1, Type2 t2, Type3 t3) {
static std::map<std::tuple<Type1, Type2, Type3>, std::function<int()>> func = {
std::make_pair(std::make_tuple(Type1::kType1_1, Type2::kType2_1, Type3::kType3_1), Caclculate<Type1::kType1_1, Type2::kType2_1, Type3::kType3_1>),
std::make_pair(std::make_tuple(Type1::kType1_1, Type2::kType2_2, Type3::kType3_1), Caclculate<Type1::kType1_1, Type2::kType2_2, Type3::kType3_1>),
};
return func[std::make_tuple(t1, t2, t3)]();
}
int main() {
CalculateHandler(kType1_1, kType2_2, kType3_1);
}
使用 for(int i;...) 然后,每次使用每個 <> 來獲得一個新變量。 那么你的代碼會更短。 注意:你必須在 for{} 中使用 <>; 否則它將無法正常工作。 如果您需要更多說明,請與我聯系。
你可以這樣做,但一般的解決方案可能比僅僅輸入它要長。
我們想將枚舉插入到模板 arguments 並得到一個組合列表:
using Input1 = Sequence<Type1_1, Type1_2>;
using Input2 = Sequence<Type2_1, Type2_2>;
using Input3 = Sequence<Type3_1, Type3_2>;
using Output = Combine<Input1, Input2, Input3>;
/* result: CombinationSet<
Combination<Type1_1, Type2_1, Type3_1>,
Combination<Type1_1, Type2_1, Type3_2>,
Combination<Type1_1, Type2_2, Type3_1>,
// etc
*/
因此,首先,定義輸入和 output 類型:
template <typename T, T... Cs>
struct Sequence {
using Type = T; //
};
// represents one iteration of Combined lists
template <typename, typename, typename>
struct Combination;
// a set of Combinations
template <typename... Ts>
struct CombinationSet;
現在,可以定義第一級:將兩個常量和一個序列轉換為一組組合。 我們可以通過偏特化推導出常量和序列的類型:
template <typename, typename, typename>
struct CombineImpl;
template <typename T1, typename T2, typename T3, T1 C1, T2 C2, T3... C3s>
struct CombineImpl<std::integral_constant<T1, C1>, std::integral_constant<T2, C2>, Sequence<T3, C3s...>>
{
using Type = CombinationSet<Combination<std::integral_constant<T1, C1>, std::integral_constant<T2, C2>, std::integral_constant<T3, C3s>>...>;
};
/* example:
CombineImpl<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
Sequence<Type3, Type3_1, Type3_2>
>
gets turned into:
CombinationSet<
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_1>
>,
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_2>
>
>
*/
現在下一個級別:如果我們有一個常量和兩個序列,我們可以多次調用CombineImpl<C, C, S>
並得到一堆CombinationSet
。 但是,我們需要一種連接所有集合的方法:
template <typename T1, typename T2, typename T3, T1 I1, T2... I2s, T3... I3s>
struct CombineImpl<std::integral_constant<T1, I1>, Sequence<T2, I2s...>, Sequence<T3, I3s...>>
{
using Type = Merge<typename CombineImpl<std::integral_constant<T1, I1>, std::integral_constant<T2, I2s>, Sequence<T3, I3s...>>::Type...>;
// ^^^^^ how to implement this?
};
我只能想到使用遞歸類型來展平集合。 可能有更好的log n
解決方案,但我不夠聰明,無法做到:
// stub - the first type is the output set, followed by input sets
template <typename... Ts>
struct MergeImpl;
// recursive bit - deduce the combinations in the next set, add to output
template <typename... TOut, typename... Ts, typename... TIn>
struct MergeImpl<CombinationSet<TOut...>, CombinationSet<Ts...>, TIn...>
{
using Type = typename MergeImpl<CombinationSet<TOut..., Ts...>, TIn...>::Type;
};
// terminal - when there are no more inputs, expose the output.
template <typename... TOut>
struct MergeImpl<CombinationSet<TOut...>>
{
using Type = CombinationSet<TOut...>;
};
// type alias to start with an empty output set
template <typename... Ts>
using Merge = typename MergeImpl<CombinationSet<>, Ts...>::Type;
/* example:
Merge<
CombinationSet<
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_1>
>,
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_2>
>
>,
CombinationSet<
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_2>,
std::integral_constant<Type2, Type2_1>
>
>
>
Gets turned into:
CombinationSet<
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_1>
>,
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_1>,
std::integral_constant<Type2, Type2_2>
>
Combination<
std::integral_constant<Type1, Type1_1>,
std::integral_constant<Type2, Type2_2>,
std::integral_constant<Type2, Type4_1>
>
>
現在定義了合並,我們可以添加另一個層來獲取三個序列的所有組合:
template <typename T1, typename T2, typename T3, T1... I1s, T2... I2s, T3... I3s>
struct CombineImpl<Sequence<T1, I1s...>, Sequence<T2, I2s...>, Sequence<T3, I3s...>>
{
using Type = Merge<typename CombineImpl<std::integral_constant<T1, I1s>, Sequence<T2, I2s...>, Sequence<T3, I3s...>>::Type...>;
};
template <typename T1, typename T2, typename T3>
using Combine = typename CombineImpl<T1, T2, T3>::Type;
下一步是從CombinationSet
創建 map。 我將再次使用部分專業化:
// stub
template <typename>
struct CalculateHandlerImpl;
// specialization - deduce combination types and declare static map
template <typename T1, typename T2, typename T3, T1... C1s, T2... C2s, T3... C3s>
struct CalculateHandlerImpl<CombinationSet<Combination<std::integral_constant<T1, C1s>, std::integral_constant<T2, C2s>, std::integral_constant<T3, C3s>>...>> {
static std::map<std::tuple<T1, T2, T3>, std::function<int()>> value;
};
// static maps have to be defined out of line
template <typename T1, typename T2, typename T3, T1... C1s, T2... C2s, T3... C3s>
std::map<std::tuple<T1, T2, T3>, std::function<int()>> CalculateHandlerImpl<CombinationSet<Combination<std::integral_constant<T1, C1s>, std::integral_constant<T2, C2s>, std::integral_constant<T3, C3s>>...>>::value = {
{ std::make_tuple(C1s, C2s, C3s), Calculate<C1s, C2s, C3s> }...
};
最后,編寫一個處理程序 function 將它們捆綁在一起:
template <typename T1, typename T2, typename T3>
int CalculateHandler(typename T1::Type t1, typename T2::Type t2, typename T3::Type t3) {
return CalculateHandlerImpl<Combine<T1, T2, T3>>::value[std::make_tuple(t1, t2, t3)]();
}
// maybe a variadic macro can help define this and the enum at the same time
using Type1Seq = Sequence<Type1,
kType1_1,
kType1_2,
kType1_3,
kType1_4,
kType1_5,
kType1_6>;
using Type2Seq = Sequence<
Type2,
kType2_1,
kType2_2,
kType2_3>;
using Type3Seq = Sequence<Type3,
kType3_1,
kType3_2,
kType3_3,
kType3_4>;
int main() {
CalculateHandler<Type1Seq, Type2Seq, Type3Seq>(kType1_1, kType2_2, kType3_1);
}
https://godbolt.org/z/r1f4886dh
現在,您會注意到所有這些模板代碼可能至少有 72 行。 另外,它肯定會增加編譯時間。 但是,如果列表增長,上述內容會有所幫助。 它可以省去檢查是否包含所有排列的麻煩。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.