簡體   English   中英

如何在C ++中將運行時類型鑒別器映射到模板實例(無需手動枚舉它們)?

[英]How in C++ to map run-time type discriminators to template instances (without manually enumerating them all)?

鑒於代表各種小類型的類型鑒別器的enum

enum TypesEnum {
    IntT, 
    DoubleT, 
    ShortStringT
};

假設我有一個template SomeType<typename A, typename B, typename C> 這是我讀取和寫入內存映射文件集的類型,其布局/跨度由類型決定; 運行時類型存儲為上面的枚舉鑒別符的三元組。

我需要編寫各種工具來加載這些文件並對它們執行操作,例如SomeType<A,B,C> => SomeType<B,A,C>等等。 因此,在這些工具中,我有一個相當尷尬的層,它將磁盤上的類型鑒別器轉換為使用模板實例為正確類型實現的通用lambdas包裝操作。

這看起來像:

static std::map< std::tuple<Discrim, Discrim, Discrim>, some_op_fn_t > = 
    {
        {std::make_tuple(IntT, DoubleT, ShortStringT), SomeOperation<int,double,char[16]>() },
         std::make_tuple(IntT, IntT, ShortStringT), SomeOperation<int,int,char[16]>() },
        ...
    };
... look up the correct function pointer and call it with the path to the files ...

其中typedef std::function<bool(void)> some_op_fn_t ,其在template<A,B,C> class SomeOperation對磁盤的副作用typedef std::function<bool(void)> some_op_fn_t工作。

現在,隨着類型列表和不同操作數量的增長,這很快變得相當繁瑣。 訣竅是我不能使用虛擬繼承來簡單地使用類型擦除的SomeType來操作抽象/虛擬值類型; 做間接和指針追逐太慢了。 我需要有航位推算和連續的,打包的值數據,適合(在浮點數和雙打的情況下)直接傳遞給BLAS。

有沒有任何技術可以自動創建這樣的接口/層? 類似於類型級別的組合會有所幫助,我可以將枚舉連接到類型一次,然后展開映射的所有實例。 那可能嗎?

最糟糕的情況我可以寫一個腳本來生成代碼,但是呃......

首先,一個簡單的部分,類型和枚舉值之間的映射:

template <typename T> struct EnumValue;

template <> struct EnumValue<int> : std::integral_constant<TypesEnum, IntT> {};
template <> struct EnumValue<double> : std::integral_constant<TypesEnum, DoubleT> {};
template <> struct EnumValue<char[16]> : std::integral_constant<TypesEnum, ShortStringT> {};

然后一個簡單的幫手功能:

using TupleT = std::tuple<int, double, char[16]>;

template <typename ... Ts> // Might be T1, T2, T3, but lazy to type
constexpr auto make_my_pair()
{
    return std::make_pair(std::make_tuple(EnumValue<Ts>::value...), &SomeOperation<Ts...>);
}

現在使用index_sequence的笛卡爾積

template <std::size_t I>
constexpr std::pair<TypesEnumTuple, some_op_fn_t>
make_my_pair()
{
    constexpr std::size_t N = std::tuple_size<TupleT>();
    return make_my_pair<
        std::tuple_element_t<(I / (N * N)) % N, TupleT>,
        std::tuple_element_t<(I / N) % N, TupleT>,
        std::tuple_element_t<(I / 1) % N, TupleT>
    >();
}

template <std::size_t ... Is>
std::map<TypesEnumTuple, some_op_fn_t>
make_my_map(std::index_sequence<Is...>)
{
    return {make_my_pair<Is>()...};
}

最后:

// 27 = std::tuple_size<TupleT>() * std::tuple_size<TupleT>() * std::tuple_size<TupleT>()
// as we have T1, T2, T3
static const std::map<TypesEnumTuple, some_op_fn_t> m =
    make_my_map(std::make_index_sequence<27>());

演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM