C++ 如何在C++;将运行时类型鉴别器映射到模板实例(而不手动全部枚举)?

C++ 如何在C++;将运行时类型鉴别器映射到模板实例(而不手动全部枚举)?,c++,c++11,template-meta-programming,C++,C++11,Template Meta Programming,给定表示各种小类型的类型鉴别器的枚举: enum TypesEnum { IntT, DoubleT, ShortStringT }; 假设我有一个模板SomeType。这是一种我读写内存映射文件集的类型,其布局/跨步由类型决定;运行时类型存储为上述枚举鉴别器的三元组 我需要编写各种工具来加载这些文件并对其执行操作,比如SomeType=>SomeType等等。因此,在这些工具中,我有一个相当笨拙的层,它将磁盘上的类型鉴别器转换为使用模板实例实现的通用lambdas

给定表示各种小类型的类型鉴别器的
枚举

enum TypesEnum {
    IntT, 
    DoubleT, 
    ShortStringT
};
假设我有一个
模板SomeType
。这是一种我读写内存映射文件集的类型,其布局/跨步由类型决定;运行时类型存储为上述枚举鉴别器的三元组

我需要编写各种工具来加载这些文件并对其执行操作,比如
SomeType=>SomeType
等等。因此,在这些工具中,我有一个相当笨拙的层,它将磁盘上的类型鉴别器转换为使用模板实例实现的通用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 ...
静态std::map
其中
typedef std::function some_op_fn_t
,其在
模板类SomeOperation
中的实现会对磁盘产生一系列副作用

现在,随着类型列表和不同操作数量的增加,这很快变得相当乏味。诀窍是我不能使用虚拟继承来简单地删除对抽象/虚拟值类型进行操作的类型
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> {};
最后:

// 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>());
//27=std::tuple\u size()*std::tuple\u size()*std::tuple\u size()
//因为我们有T1,T2,T3
静态常量std::map m=
make_my_map(std::make_index_sequence());

简单的部分:你可能有一个特征可以映射到
enum
IntT
int
double
double
(或者反之亦然)。更复杂的部分是枚举的笛卡尔积。嗯,我可以看到从
IntT
int
的特征映射,但只有在编译时?即使我有一个乘积枚举元组的向量,我仍然不能在上面循环添加
map.insert({I,SomeOperation()})
correct?那么,为什么你认为
std::function
会比vtable查找快得多呢?是不是
std::function
可以在压缩内存上运行,而vtables(据您所知)需要堆/空闲存储分配?vtable只是一个指针,指向在极端情况下具有特殊布局的函数表。第二,如果你的解决方案变得单调乏味怎么办?“这变得乏味”就像“这不管用”;手工输入这些结构是否有问题?
std::function
只是包装初始调用,关键是
SomeOperation
内部需要知道其类型。我一开始并不关心间接寻址,我只是不能在
SomeOperation
SomeType
的内部有任何间接寻址。是的,问题是,当我向系统添加操作并向枚举添加类型时,维护这些表变得很麻烦。太棒了,谢谢。现在我将尝试在
SomeOperation
/
someop\fn\t
std::size\u t compile\u time\u pow(std::size\u t a,std::size\u t b)
可能比
27
更好?我还将
TupleT
作为一个类型模板参数,也可能是
std::integral_constant
的别名,但这只是清理。
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>());