Как написать концепцию C ++, ограничивающую шаблон до std :: map и std :: unordered_map

Если у меня есть такие шаблоны, которые выполняют простую операцию копирования для примера, но для std::map и 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;
}

Есть ли способ, возможно, используя концепции C ++, сократить эти определения до одного, ограничив возможные типы только std::map и std::unordered_map?


person Anton Kochkov    schedule 27.09.2020    source источник


Ответы (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<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;
}
person Artyer    schedule 27.09.2020
comment
Интересный подход. Интересно, а в стандартной библиотеке такого помощника нет ... - person Anton Kochkov; 27.09.2020
comment
@AntonKochkov, я думаю, это был либо кандидат на std :: experimental, либо на расширение библиотеки, по крайней мере, это дает deja vue - person Swift - Friday Pie; 27.09.2020
comment
Хотя это работает только тогда, когда все параметры шаблона являются параметрами типа. Например, он не может определить специализацию std::array. - person aschepler; 28.09.2020

Вы можете добавить ограничение,

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;
}
person songyuanyao    schedule 27.09.2020
comment
Можно ли выделить концептуальное ограничение в отдельный пункт с concept Mappable = requires {...}? - person Anton Kochkov; 27.09.2020
comment
@AntonKochkov Да, ответ исправлен. - person songyuanyao; 27.09.2020
comment
Вы также можете создать концепцию, взяв в качестве аргумента только тип контейнера - что может быть более полезно, если у вас есть несколько объявлений, которые будут его использовать. Его определение должно использовать вспомогательную черту. - person aschepler; 27.09.2020
comment
@aschepler Я думаю, было бы неплохо дать ответ с альтернативным подходом - тем, который вы предложили. - person Fureeish; 27.09.2020
comment
Это плохая концепция. Обычно то, что вы хотите от концептов, не относится к этому конкретному типу? а можно ли использовать этот тип так, как я их использую? - person Guillaume Racicot; 27.09.2020