类地图容器和类向量容器之间的歧义模板专业化 [英] Disambiguate template specialization between map-like and vector-like containers

查看:74
本文介绍了类地图容器和类向量容器之间的歧义模板专业化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  template< class> struct打印机; 

//我希望它与std :: vector(和类似的线性容器)匹配
template< template< class,class ...> T类,TV类,类... TS>
struct Printer< T< TV,TS ...> {...};

//我希望它与std :: map(和类似的类似地图的容器)匹配
template< template< template,class,class,class ...> TM类,TK类,TV类,类型名称... TS>
struct Printer< TK,TV,TS ...> {...}

int main()
{
//两者都与第二个专业化匹配,后者仅用于
// std ::地图(以及类似的类似地图的容器)
Printer< std :: vector< int>> :: something();
Printer< std :: map< int,float>> ::: something();
}

从示例中可以看到, std: :vector std :: map 都与第二个专业化匹配。我认为这是因为 std :: vector 的分配器参数与 TV 匹配,后者旨在用于 std :: map 的值。



如何将 std :: vector (和其他线性容器)


<,第一个专业化标签和 std :: map (以及其他键值容器)? div class = h2_lin>解决方案

模式匹配方法的问题在于,只有为每个编写了专门化的容器的容器,它才有效。



相反,您可以依靠其他属性:




  • 容器必须可以通过 begin(c) end(c)表达式
  • $ b进行迭代$ b
  • 最重要的是,关联容器将具有 :: key_type 嵌套类型,如§23.2.4 [associative .rqmts]



因此,我们可以基于标签分发 >:

 内联constexpr auto is_container_impl(...)-> std :: false_type {
return std :: false_type {};
}

模板< typename C>
constexpr auto is_container_impl(C const * c)->
decltype(begin(* c),end(* c),std :: true_type {})
{
return std :: true_type {};
}

模板< typename C>
constexpr auto is_container(C const& c)-> decltype(is_container_impl(& c)){
return is_container_impl(& c);
}

内联constexpr自动is_associative_container_impl(...)
-> std :: false_type
{return std :: false_type {}; }

模板< typename C,typename = typename C :: key_type>
constexpr auto is_associative_container_impl(C const *)-> std :: true_type {
return std :: true_type {};
}

模板< typename C>
constexpr auto is_associative_container(C const& c)
-> decltype(is_associative_container_impl(& c))
{
return is_associative_container_impl(& c);
}

现在您可以编写简单代码:

 模板< typename C> 
void print_container(C const& c,std :: false_type / * is_associative * /){
}

模板< typename C>
void print_container(C const& c,std :: true_type / * is_associative * /){
}

模板< typename C>
void print_container(C const& c){
return print_container(C,is_assocative_container(c));
}

现在,这可能并不是您想要的,因为在此要求下集合是一个关联容器,但它的值不是,因此无法打印键:值。您必须根据需要调整标签分配。


template<class> struct Printer;

// I want this to match std::vector (and similar linear containers) 
template<template<class, class...> class T, class TV, class... TS> 
    struct Printer<T<TV, TS...>> { ... };

// I want this to match std::map (and similar map-like containers)
template<template<class, class, class...> class TM, class TK, class TV, typename... TS> 
    struct Printer<TM<TK, TV, TS...>> { ... }

int main() 
{
    // Both of these match the second specialization, which is only intended
    // for std::map (and similar map-like containers)
    Printer<std::vector<int>>::something();
    Printer<std::map<int, float>>::something();
}

As you can see from the example, std::vector and std::map both match the second specialization. I think it's because std::vector's allocator parameter gets matched to TV, which is intended for std::map's value.

How can I match std::vector (and other linear containers) with the first specialization and std::map (and other key-value containers) with the second one?

解决方案

The problem with the pattern-matching approach is that it will only ever work if for every single container you write a specialization. This is tedious work.

Instead you can rely on other properties:

  • a container will necessarily be iterable over via begin(c) and end(c) expressions
  • on top of this, an associative container will have a ::key_type nested type, among others, as expressed in § 23.2.4 [associative.rqmts].

Therefore, we can whip up a classifier, based on tag dispatching:

inline constexpr auto is_container_impl(...) -> std::false_type {
    return std::false_type{};
}

template <typename C>
constexpr auto is_container_impl(C const* c) ->
    decltype(begin(*c), end(*c), std::true_type{})
{
    return std::true_type{};
}

template <typename C>
constexpr auto is_container(C const& c) -> decltype(is_container_impl(&c)) {
    return is_container_impl(&c);
}

inline constexpr auto is_associative_container_impl(...)
    -> std::false_type
{ return std::false_type{}; }

template <typename C, typename = typename C::key_type>
constexpr auto is_associative_container_impl(C const*) -> std::true_type {
    return std::true_type{};
}

template <typename C>
constexpr auto is_associative_container(C const& c)
    -> decltype(is_associative_container_impl(&c))
{
    return is_associative_container_impl(&c);
}

And now you can write "simple" code:

template <typename C>
void print_container(C const& c, std::false_type/*is_associative*/) {
}

template <typename C>
void print_container(C const& c, std::true_type/*is_associative*/) {
}

template <typename C>
void print_container(C const& c) {
    return print_container(C, is_assocative_container(c));
}

Now, this might not be exactly what you wish for, because under this requirements a set is an associative container, but its value is not a pair, so you cannot print key: value. You have to adapt the tag-dispatching to your needs.

这篇关于类地图容器和类向量容器之间的歧义模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆