std :: map ,具有从KeyType到ValueType的映射

问题描述 投票:-1回答:1

我正在尝试创建从std::mapKeyType的映射的变体MappedType到变体。

此选项最多可用于大约100种键类型:https://coliru.stacked-crooked.com/a/3959534e4fa38caa。当我尝试使用200个键类型进行编译时,GCC会苦思一段时间,然后放弃该错误:

g++: internal compiler error: Killed (program cc1plus)

我相信参数包太大可能是个问题。是否有更可扩展的解决方案?

我在解决方案的主要部分下面包括:

template<typename Key, typename T>
struct TypeMap {
    using KeyType = Key;
    using MappedType = T;
};

template<typename>
constexpr bool false_v = false;

// End case
template<typename Key, typename...>
struct MappedTypeForKey {
    static_assert(false_v<Key>, "Container mapping for key type not found");
};

// Recursive case
template<typename Key, typename MapKey, typename T, typename... TypeMaps>
struct MappedTypeForKey<Key, TypeMap<MapKey, T>, TypeMaps...> : MappedTypeForKey<Key, TypeMaps...> {
};

// Match case
template<typename Key, typename T, typename... TypeMaps>
struct MappedTypeForKey<Key, TypeMap<Key, T>, TypeMaps...> {
    using Type = T;
};

template<typename... TypeMaps>
struct VariantTypeMapImpl {
    using KeyType = std::variant<typename TypeMaps::KeyType...>;
    using MappedType = std::variant<typename TypeMaps::MappedType...>;
    template<typename Key>
    using TypeForKey = typename MappedTypeForKey<Key, TypeMaps...>::Type;
};

// This is the key part of the code, allowing a developer to extend the map variants
// at the same time as defining the type mappings:
using VariantTypeMap = VariantTypeMapImpl<
    TypeMap<FrogKey, Frog>,
    TypeMap<CatKey, Cat>
>;

class VariantMap {
  public:
    size_t size() const { return map_.size(); }

    template<typename Key>
    void insert(Key key, VariantTypeMap::TypeForKey<Key> value)
    {
        map_.emplace(std::move(key), std::move(value));
    }

    template<typename Key>
    const VariantTypeMap::TypeForKey<Key>& get(const Key& key) const
    {
        return std::get<VariantTypeMap::TypeForKey<Key>>(map_.at(key));
    }

  private:
    std::map<VariantTypeMap::KeyType, VariantTypeMap::MappedType> map_;
};
c++ variadic-templates type-safety
1个回答
0
投票

如果实际上对于所有MappedTypeForKey类型都实例化了insertget,则需要二次方Key的多个实例化。最终,GCC将耗尽内存来存储这些实例化和崩溃。

相反,您可以通过使用基类的模板参数推导规则来映射到类型。如果编译器已很好地实现了此基类查找,则将花费子线性时间,从而使整个程序有望不再具有二次编译时间和内存复杂性:

template<typename... TypeMaps>
struct VariantTypeMapImpl {
    using KeyType = std::variant<typename TypeMaps::KeyType...>;
    using MappedType = std::variant<typename TypeMaps::MappedType...>;

    template<typename, typename>
    struct entry {};

    struct MappedTypeForKey
      : entry<TypeMaps::KeyType, KeyType::MappedType>... {
        template<typename Key, typename Mapped>
        static auto lookup(const entry<Key, Mapped>&) -> Mapped;
    };

    template<typename Key>
    using TypeForKey = decltype(MappedTypeForKey::lookup<Key>(MappedTypeForKey{}));
};
© www.soinside.com 2019 - 2024. All rights reserved.