Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

To get started, I'd like to write a type trait that is true for a vector and false otherwise. I tried this, but it doesn't compile:

template<class T, typename Enable = void> struct is_vector {   static bool const value = false; };  template<class T, class U> struct is_vector<T, typename boost::enable_if<boost::is_same<T, std::vector<U> > >::type> {   static bool const value = true; }; 

The error message is template parameters not used in partial specialization: U.

like image 343
Frank Avatar asked Aug 20 '12 18:08

Frank


People also ask

What is a type trait?

What is a type trait? A type trait is a simple template struct that contains a member constant, which in turn holds the answer to the question the type trait asks or the transformation it performs.

How do type traits work C++?

The type-traits library also contains a set of classes that perform a specific transformation on a type; for example, they can remove a top-level const or volatile qualifier from a type. Each class that performs a transformation defines a single typedef-member type that is the result of the transformation.


2 Answers

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.

UPDATE. As @Deduplicator noted, container might not meet AllocatorAwareContainer requirements (e.g.: std::array<T, N>). That is why check on T::allocator_type is not neccessary. But you may check any/all Container requirements in a similar way.

like image 60
Nevermore Avatar answered Sep 21 '22 05:09

Nevermore


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?

like image 24
Frank Avatar answered Sep 20 '22 05:09

Frank