【问题标题】:How to write a C++ concept restricting the template to std::map and std::unordered_map如何编写将模板限制为 std::map 和 std::unordered_map 的 C++ 概念
【发布时间】:2020-09-27 11:27:51
【问题描述】:

如果我有一个看起来像这样的模板,为了示例而执行简单的复制操作,但对于 std::mapstd::unordered_map

template<typename T1, typename T2>
inline std::map<T1, T2> map_copy(std::map<T1,T2> const& a) {
  std::map<T1,T2> output;
  output = a;
  return output;
}

template<typename T1, typename T2>
inline std::unordered_map<T1, T2> map_copy(std::unordered_map<T1,T2> const& a) {
  std::unordered_map<T1,T2> output;
  output = a;
  return output;
}

有没有办法(可能使用 C++ 概念)将这些定义简化为一个,将可能的类型限制为 std::mapstd::unordered_map

【问题讨论】:

    标签: c++ c++20 c++-concepts


    【解决方案1】:

    你可以添加一个约束,

    template<template <typename...> class MAP, typename T1, typename T2>
    inline MAP<T1, T2> map_copy(MAP<T1,T2> const& a) 
      requires std::is_same_v<MAP<T1,T2>, std::map<T1,T2>> || 
        std::is_same_v<MAP<T1,T2>, std::unordered_map<T1,T2>> {
      MAP<T1,T2> output;
      output = a;
      return output;
    }
    

    或者定义一个概念,

    template<template <typename...> class MAP, typename T1, typename T2>
    concept Mappable = std::is_same_v<MAP<T1,T2>, std::map<T1,T2>> ||
      std::is_same_v<MAP<T1,T2>, std::unordered_map<T1,T2>>;
    

    然后

    template <template <typename...> class MAP, typename T1, typename T2>
    inline MAP<T1, T2> map_copy(MAP<T1,T2> const& a) requires Mappable<MAP, T1, T2> {
      MAP<T1,T2> output;
      output = a;
      return output;
    }
    

    【讨论】:

    • 是否可以将概念限制提取到带有concept Mappable = requires {...}的单独子句中?
    • @AntonKochkov 是的,答案已修改。
    • 您还可以创建一个仅将容器类型作为参数的概念 - 如果您有多个要使用它的声明,可能会更有用。它的定义需要使用辅助特征。
    • @aschepler 我认为用您建议的替代方法提供答案是个好主意。
    • 这不是一个好概念。通常你想要的概念不是“它是这种特殊类型吗?”而是“可以像我使用它们的方式使用这种类型吗?”
    【解决方案2】:

    您可以使用这个概念来检查一个类型是std::map 还是std::unordered_map

    template<typename T>
    concept map_type = 
        std::same_as<T, std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>> ||
        std::same_as<T, std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::hasher, typename T::key_equal, typename T::allocator_type>>;
        
    template<map_type T>
    T map_copy(T const& a) {
        T output;
        output = a;
        return output;
    }
    

    对于一般检查 T 是否是 template&lt;typename...&gt; struct Template; 的实例化,您可以执行以下操作:

    template<template<typename...> class Template, typename Class>
    struct is_instantiation : std::false_type {};
    
    template<template<typename...> class Template, typename... Args>
    struct is_instantiation<Template, Template<Args...>> : std::true_type {};
    
    template<typename Class, template<typename...> class Template>
    concept is_instantiation_of = is_instantiation<Template, Class>::value;
    
    template<typename T>
    concept map_type =
        is_instantiation_of<T, std::map> || is_instantiation_of<T, std::unordered_map>;
    
    template<map_type T>
    T map_copy(T const& a) {
        T output;
        output = a;
        return output;
    }
    
    template<is_instantiation_of<std::map> T>
    T ordered_map_copy(T const& a) {
        return a;
    }
    

    【讨论】:

    • 有趣的方法。我想知道标准库中是否没有这样的助手...
    • @AntonKochkov 我认为它要么是 std::experimental 的候选者,要么是提升库的候选者,至少它提供了似曾相识
    • 虽然它只在模板的参数都是类型参数时才有效。例如,它无法检测到 std::array 特化。
    猜你喜欢
    • 2022-01-13
    • 2018-05-31
    • 2021-11-02
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 2022-09-23
    • 2010-10-08
    相关资源
    最近更新 更多