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

前端 未结 10 1313
不知归路
不知归路 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:53

    If you also want to make it work for const std::vector, you can use the following:

    namespace local {
    
    template<typename T, typename _ = void>
    struct isVector: std::false_type {
    };
    
    template<typename T>
    struct isVector<T,
            typename std::enable_if<
                    std::is_same<typename std::decay<T>::type, std::vector<typename std::decay<T>::type::value_type, typename std::decay<T>::type::allocator_type> >::value>::type> : std::true_type {
    };
    
    }
    
    TEST(TypeTraitTest, testIsVector) {
        ASSERT_TRUE(local::isVector<std::vector<int>>::value);
        ASSERT_TRUE(local::isVector<const std::vector<int>>::value);
    
        ASSERT_FALSE(local::isVector<std::list<int>>::value);
        ASSERT_FALSE(local::isVector<int>::value);
    
        std::vector<uint8_t> output;
        std::vector<uint8_t> &output2 = output;
        EXPECT_TRUE(core::isVector<decltype(output)>::value);
        EXPECT_TRUE(core::isVector<decltype(output2)>::value);
    }
    

    Without the std::remove_cv call the second ASSERT_TRUE would fail. But of course this depends on your needs. The thing here is that according to the specs, std::is_same checks for const and volatile to also match.

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

    You would say that it should be simpler than that...

    template <typename T, typename _ = void>
    struct is_vector { 
        static const bool value = false;
    };
    template <typename T>
    struct is_vector< T,
                      typename enable_if<
                          is_same<T,
                                  std::vector< typename T::value_type,
                                               typename T::allocator_type >
                                 >::value
                      >::type
                    >
    {
        static const bool value = true;
    };
    

    ... But I am not really sure of whether that is simpler or not.

    In C++11 you can use type aliases (I think, untested):

    template <typename T>
    using is_vector = is_same<T, std::vector< typename T::value_type,
                                              typename T::allocator_type > >;
    

    The problem with your approach is that the type U is non-deducible in the context where it is used.

    0 讨论(0)
  • 2020-11-27 15:00

    While the other answers here that try to guess whether a class is a container or not might work for you, I would like to present you with the alternative of naming the type you want to return true for. You can use this to build arbitrary is_(something) traits types.

    template<class T> struct is_container : public std::false_type {};
    
    template<class T, class Alloc> 
    struct is_container<std::vector<T, Alloc>> : public std::true_type {};
    
    template<class K, class T, class Comp, class Alloc> 
    struct is_container<std::map<K, T, Comp, Alloc>> : public std::true_type {};
    

    And so on.

    You will need to include <type_traits> and whatever classes you add to your rules.

    0 讨论(0)
  • 2020-11-27 15:06

    In our project we still didn't manage to migrate to compiler supporting C++11, so for type_traits of container objects I had to wrote a simple boost style helper:

    template<typename Cont> struct is_std_container: boost::false_type {};
    template<typename T, typename A> 
    struct is_std_container<std::vector<T,A> >: boost::true_type {};
    template<typename T, typename A> 
    struct is_std_container<std::list<T,A> >: boost::true_type {};
    template<typename T, typename A> 
    struct is_std_container<std::deque<T,A> >: boost::true_type {};
    template<typename K, typename C, typename A> 
    struct is_std_container<std::set<K,C,A> >: boost::true_type {};
    template<typename K, typename T, typename C, typename A> 
    struct is_std_container<std::map<K,T,C,A> >: boost::true_type {};
    
    template<typename Cont> struct is_std_sequence: boost::false_type {};
    template<typename T, typename A> 
    struct is_std_sequence<std::vector<T,A> >: boost::true_type {};
    template<typename T, typename A> 
    struct is_std_sequence<std::list<T,A> >: boost::true_type {};
    template<typename T, typename A> 
    struct is_std_sequence<std::deque<T,A> >: boost::true_type {};
    
    0 讨论(0)
提交回复
热议问题