How to write a type trait `is_container` or `is_vector`?

前端 未结 10 1305
不知归路
不知归路 2020-11-27 14:11

Is it possible to write a type trait whose value is true for all common STL structures (e.g., vector, set, map, ...)?

To get s

相关标签:
10条回答
  • 2020-11-27 14:40

    Why not do something like this for is_container?

    template <typename Container>
    struct is_container : std::false_type { };
    
    template <typename... Ts> struct is_container<std::list<Ts...> > : std::true_type { };
    template <typename... Ts> struct is_container<std::vector<Ts...> > : std::true_type { };
    // ...
    

    That way users can add their own containers by partially-specializing. As for is_vector et-al, just use partial specialization as I did above, but limit it to only one container type, not many.

    0 讨论(0)
  • 2020-11-27 14:45

    Fast forward to 2018 and C++17, I was so daring to improve on @Frank answer

    // clang++ prog.cc -Wall -Wextra -std=c++17
    
     #include <iostream>
     #include <vector>
    
     namespace dbj {
        template<class T>
          struct is_vector {
            using type = T ;
            constexpr static bool value = false;
       };
    
       template<class T>
          struct is_vector<std::vector<T>> {
            using type = std::vector<T> ;
            constexpr  static bool value = true;
       };
    
      // and the two "olbigatory" aliases
      template< typename T>
         inline constexpr bool is_vector_v = is_vector<T>::value ;
    
     template< typename T>
        using is_vector_t = typename is_vector<T>::type ;
    
     } // dbj
    
       int main()
    {
       using namespace dbj;
         std::cout << std::boolalpha;
         std::cout << is_vector_v<std::vector<int>> << std::endl ;
         std::cout << is_vector_v<int> << std::endl ;
    }   /*  Created 2018 by dbj@dbj.org  */
    

    The "proof the pudding". There are better ways to do this, but this works for std::vector.

    0 讨论(0)
  • 2020-11-27 14:48

    The way I like to detect whether something is a container is to look for data() and size() member functions. Like this:

    template <typename T, typename = void>
    struct is_container : std::false_type {};
    
    template <typename T>
    struct is_container<T
       , std::void_t<decltype(std::declval<T>().data())
          , decltype(std::declval<T>().size())>> : std::true_type {};
    
    0 讨论(0)
  • 2020-11-27 14:49

    Actually, after some trial and error I found it's quite simple:

    template<class T>
    struct is_vector<std::vector<T> > {
      static bool const value = true;
    };
    

    I'd still like to know how to write a more general is_container. Do I have to list all types by hand?

    0 讨论(0)
  • 2020-11-27 14:49
    template <typename T>
    struct is_container {
    
        template <
           typename U,
           typename I = typename U::const_iterator
        >   
        static int8_t      test(U* u); 
    
        template <typename U>
        static int16_t     test(...);
    
        enum { value  =  sizeof test <typename std::remove_cv<T>::type> (0) == 1 };
    };
    
    
    template<typename T, size_t N>  
    struct  is_container <std::array<T,N>>    : std::true_type { };
    
    0 讨论(0)
  • 2020-11-27 14:53

    Look, another SFINAE-based solution for detecting STL-like containers:

    template<typename T, typename _ = void>
    struct is_container : std::false_type {};
    
    template<typename... Ts>
    struct is_container_helper {};
    
    template<typename T>
    struct is_container<
            T,
            std::conditional_t<
                false,
                is_container_helper<
                    typename T::value_type,
                    typename T::size_type,
                    typename T::allocator_type,
                    typename T::iterator,
                    typename T::const_iterator,
                    decltype(std::declval<T>().size()),
                    decltype(std::declval<T>().begin()),
                    decltype(std::declval<T>().end()),
                    decltype(std::declval<T>().cbegin()),
                    decltype(std::declval<T>().cend())
                    >,
                void
                >
            > : public std::true_type {};
    

    Of course, you might change methods and types to be checked.

    If you want to detect only STL containers (it means std::vector, std::list, etc) you should do something like this.

    0 讨论(0)
提交回复
热议问题