Disambiguate template specialization between map-like and vector-like containers

前端 未结 3 649
孤独总比滥情好
孤独总比滥情好 2021-01-01 18:43
template struct Printer;

// I want this to match std::vector (and similar linear containers) 
template class T, clas         


        
3条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-01 19:35

    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 
    constexpr auto is_container_impl(C const* c) ->
        decltype(begin(*c), end(*c), std::true_type{})
    {
        return std::true_type{};
    }
    
    template 
    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 
    constexpr auto is_associative_container_impl(C const*) -> std::true_type {
        return std::true_type{};
    }
    
    template 
    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 
    void print_container(C const& c, std::false_type/*is_associative*/) {
    }
    
    template 
    void print_container(C const& c, std::true_type/*is_associative*/) {
    }
    
    template 
    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.

提交回复
热议问题