【问题标题】:Use std::type_index as value in a map使用 std::type_index 作为映射中的值
【发布时间】:2018-02-22 04:00:30
【问题描述】:

我正在尝试创建一个std::unordered_map,其中std::type_index。以下 sn-p 有效:

std::unordered_map<std::type_index, int> workingMap;
workingMap[typeid(int)] = 1;
workingMap[typeid(char)] = 2;

但是这个没有运行并抛出错误:

std::unordered_map<int, std::type_index> failingMap;
failingMap[1] = typeid(int);
failingMap[2] = typeid(char);

CS2512:“std::type_index::type_index”:没有合适的默认构造函数可用。

我不完全理解这个错误,这些例子中的构造函数有什么区别?是否可以制作一张 typeid(..)value 而不是 key 的地图?

【问题讨论】:

  • 通过failingMap[1] 创建一个默认条目,如果它在地图中没有找到。以::try_emplace 为例

标签: c++ c++11 constructor rtti typeinfo


【解决方案1】:

问题是operator[],不是地图的实际使用。问题是如果找不到键,operator[] 将分配一个默认值并返回对该值的可修改引用,而std::type_index 则不可能。您可以使用 emplaceinserttry_emplace 或任何其他不需要默认构造函数的修饰符。

【讨论】:

    【解决方案2】:

    当然,我们总是可以为 type_info 创建一个可为空的包装器。

    #include <typeindex>
    #include <functional>
    #include <unordered_map>
    #include <cassert>
    
    
    struct nullable_type_index
    {
        constexpr nullable_type_index() : ptr_(nullptr) {}
        constexpr nullable_type_index(std::type_info const& ti) : ptr_(std::addressof(ti)) {}
    
        constexpr operator bool() const
        {
            return bool(ptr_);
        }
    
        // I have avoided implicit conversion, but it could probably work
        // without any surprises.
        std::type_info const& get_type_info() const {
            assert(ptr_);
            return *ptr_;
        }
    
        constexpr bool operator==(nullable_type_index const& other) const {
            return ptr_ && other.ptr_ 
            ? *ptr_ == *other.ptr_
            : ptr_ == other.ptr_;
        }
    
    private:
        std::type_info const* ptr_;
    };
    
    std::size_t hash_value(const nullable_type_index& nti)
    {
        return nti ? 0 : nti.get_type_info().hash_code();
    }
    
    bool operator==(nullable_type_index const& l, std::type_info const& r)
    {
        return l == nullable_type_index(r);
    }
    
    bool operator==(std::type_info const& l, nullable_type_index const& r)
    {
        return nullable_type_index(l) == r;
    }
    
    namespace std {
    
        template<>
        struct hash<nullable_type_index>
        {
            std::size_t operator()(nullable_type_index const& arg) const {
                return hash_value(arg);
            }
        };
    }
    
    int main()
    {
        std::unordered_map<std::type_index, int> workingMap;
        workingMap[typeid(int)] = 1;
        workingMap[typeid(char)] = 2;    
    
        std::unordered_map<int, nullable_type_index> failingMap;
        failingMap[1] = typeid(int);
        failingMap[2] = typeid(char);
    }
    

    当然,现在我们有了 std::optional...

    int main()
    {
        std::unordered_map<std::type_index, int> workingMap;
        workingMap[typeid(int)] = 1;
        workingMap[typeid(char)] = 2;    
    
        std::unordered_map<int, std::optional<std::type_index>> failingMap;
        failingMap[1] = typeid(int);
        failingMap[2] = typeid(char);
    }
    

    【讨论】:

    • 这是std::optional 的一个很好的答案,C++11 的反向移植存在于单个标头中(以及 C++03 的 Boost 版本)。老实说,我认为可以为空的版本是矫枉过正的,因为存在优秀的替代品。不过,很好的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-08-19
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 2018-04-24
    • 2014-05-15
    • 1970-01-01
    • 2022-08-03
    相关资源
    最近更新 更多