没有提升的自定义 type_index 订单

custom type_index order without boost

我有以下地图:

std::map<std::type_index, std::set<Status *>> statuses;

由于 std::type_index,它在那里存储了 Status 的不同子集class。 但是我想控制这个地图中对象的顺序(例如,我有两个 classes BurnStun 继承自 Status,我想要 typeid(Stun) < typeif(Burn) 这样当我遍历地图时我会在 std::set<Burn>).

之前得到 std::set<Stun>

我想过实现一个自定义 type_index class 但我似乎找不到任何方法来做到这一点而不需要提升,这是一个巨大的库,我希望不必包含到我的项目中。

关于如何在地图中自定义顺序有什么建议吗?

您可以将 type_index 包装到自定义类型中,并使用可生成所需顺序的比较器。

cppreference 中的示例使用 std::map 而不是 std::unordered_map 并使用自定义比较器进行了修改:

#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
#include <memory>
 
struct A {
    virtual ~A() {}
};
 
struct B : A {};
struct C : A {};

struct my_type_index {
    std::type_index index = std::type_index(typeid(void));
    my_type_index() = default;
    my_type_index(std::type_index i) : index(i) {}
    bool operator<(const my_type_index& other) const {
        static std::map< std::type_index,int> rank{
            { std::type_index(typeid(A)) , 1},
            { std::type_index(typeid(B)),  2},
            { std::type_index(typeid(double)),  3},
            { std::type_index(typeid(int)),  4},
            { std::type_index(typeid(C)),  5}
        };        
        return rank[index] < rank[other.index];
    }
};


int main()
{
    std::map<my_type_index, std::string> type_names;
 
    type_names[std::type_index(typeid(int))] = "int";
    type_names[std::type_index(typeid(double))] = "double";
    type_names[std::type_index(typeid(A))] = "A";
    type_names[std::type_index(typeid(B))] = "B";
    type_names[std::type_index(typeid(C))] = "C";
   
    for (const auto& e : type_names) {
        std::cout << e.first.index.name() << " " << e.second << "\n";
    }
}

output:

1A A
1B B
d double
i int
1C C

François Andrieux 建议的改进:

struct my_type_index {
    std::type_index index = std::type_index(typeid(void));
    int rank = 0;
    my_type_index() = default;
    my_type_index(std::type_index i) : index(i) {
        auto it = ranks.find(i);
        if (it != ranks.end()) rank = it->second;
    }
    
    static const std::map<std::type_index,int> ranks;
    
    bool operator<(const my_type_index& other) const {        
        return rank < other.rank;
    }
};

const std::map<std::type_index,int> my_type_index::ranks = [](){
    std::map<std::type_index,int> result;
    std::type_index index_order[] = {
        std::type_index(typeid(A)),
        std::type_index(typeid(B)),
        std::type_index(typeid(double)),
        std::type_index(typeid(int)),
        std::type_index(typeid(C)) 
    };
    for (size_t i = 0; i < std::size(index_order);++i){ result[ index_order[i]] = i+1; }
    return result;
}();

排名存储在静态地图中 ranks 并且每个实例 rank 已经在构建时进行了评估(而不是在每次比较时进行评估,即比较现在更便宜)。此外,地图现在是从一个数组生成的,它更强大(您不能再错误输入 index/rank)。此外,映射是 const,即 find 而不是 operator[] 用于查找。不在地图中的元素将被分配为 0 级。实际上以前也是如此,但在 operator[] 之前可能会向地图添加不必要的元素。