如何编写将模板限制为 std::map 和 std::unordered_map 的 C++ 概念

Ant*_*kov 6 c++ c++-concepts c++20

如果我有一个看起来像这样的模板,为了示例而执行简单的复制操作,但对于std::mapand std::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;
}
Run Code Online (Sandbox Code Playgroud)

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

Art*_*yer 6

您可以使用这个概念来检查类型是否是 astd::mapstd::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;
}
Run Code Online (Sandbox Code Playgroud)

对于通用检查 ifT是 的实例化template<typename...> 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;
}
Run Code Online (Sandbox Code Playgroud)


son*_*yao 5

您可以添加一个约束,

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;
}
Run Code Online (Sandbox Code Playgroud)

或者定义一个概念,

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>>;
Run Code Online (Sandbox Code Playgroud)

然后

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好概念。通常你想要的概念不是“它是这种特定类型的吗?” 而是“这种类型可以像我使用它们的方式使用吗?” (3认同)
  • 是否可以使用“concept Mappable = require {...}”将概念限制提取到单独的子句中? (2认同)
  • 您还可以创建一个仅将容器类型作为参数的概念 - 如果您有多个要使用它的声明,可能会更有用。它的定义需要使用辅助特征。 (2认同)