Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if a type is an STL container at compile time

Tags:

I would like to write a template that will determine if a type is an stl container at compile time.  

I've got the following bit of code:

struct is_cont{}; struct not_cont{};  template <typename T> struct is_cont { typedef not_cont result_t; }; 

but I'm not sure how to create the necessary specializations for std::vector<T,Alloc>, deque<T,Alloc>, set<T,Alloc,Comp> etc...

like image 812
Xander Tulip Avatar asked Feb 23 '12 04:02

Xander Tulip


People also ask

Which of the following are STL containers types?

The three types of containers found in the STL are sequential, associative and unordered.

What are the types of STL containers in C++?

In C++, there are generally 3 kinds of STL containers: Sequential Containers. Associative Containers. Unordered Associative Containers.


2 Answers

Note: the following code is taken from an excellent utility called pretty-print written by @Kerrek SB (a topic on it at stackoverflow).

Disclaimer : I don't know if I'm allowed to copy and paste this code here without taking permission from the original author. @Kerrek, let me know if you've any issue. :-)


You can use this classs template:

  template<typename T>    struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value>    { }; 

Usage:

 std::cout << is_container<std::vector<int>>::value << std::endl; //true  std::cout << is_container<std::list<int>>::value << std::endl;   //true   std::cout << is_container<std::map<int>>::value << std::endl;    //true  std::cout << is_container<std::set<int>>::value << std::endl;    //true  std::cout << is_container<int>::value << std::endl;              //false 

Note that is_container needs following helper class templates:

template<typename T> struct has_const_iterator { private:     typedef char                      yes;     typedef struct { char array[2]; } no;      template<typename C> static yes test(typename C::const_iterator*);     template<typename C> static no  test(...); public:     static const bool value = sizeof(test<T>(0)) == sizeof(yes);     typedef T type; };  template <typename T> struct has_begin_end {     template<typename C> static char (&f(typename std::enable_if<       std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),       typename C::const_iterator(C::*)() const>::value, void>::type*))[1];      template<typename C> static char (&f(...))[2];      template<typename C> static char (&g(typename std::enable_if<       std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),       typename C::const_iterator(C::*)() const>::value, void>::type*))[1];      template<typename C> static char (&g(...))[2];      static bool const beg_value = sizeof(f<T>(0)) == 1;     static bool const end_value = sizeof(g<T>(0)) == 1; }; 
like image 96
Nawaz Avatar answered Sep 28 '22 01:09

Nawaz


First, you define your primary template, which will have a member which is false in the default case:

template <typename T> struct is_cont {   static const bool value = false; }; 

Then you will define partial specializations for your container types which have a value of true instead:

template <typename T,typename Alloc> struct is_cont<std::vector<T,Alloc> > {   static const bool value = true; }; 

Then for a type X that you want to check, use it like

if (is_cont<X>::value) { ... }  
like image 27
Vaughn Cato Avatar answered Sep 28 '22 01:09

Vaughn Cato