Is_container attribute error when calling std :: set SFINAE

I am trying to write a stream statement for std containers, mainly for debugging purposes.

I have the following code:

#include <type_traits> #include <iostream> #include <ostream> #include <iterator> #include <algorithm> #include <functional> #include <vector> #include <set> #include <deque> template<typename Container> struct is_container { typedef char no; typedef long yes; template<typename A, A, A> struct is_of_type; template<typename T> static yes& is_cont( is_of_type < typename T::iterator(T::*)(), &T::begin, &T::end >*); template<typename T> static no& is_cont(...); //any other template<typename C, bool B> struct is_class_is_container { const static bool value=sizeof( is_cont<C>(nullptr) )==sizeof(yes); }; template<typename C> struct is_class_is_container<C, false> { const static bool value=false; }; const static bool value = is_class_is_container < Container, std::is_class<Container>::value >::value; }; template<typename T> typename std::enable_if < is_container<T>::value, std::ostream >::type& operator<<(std::ostream& os, const T& a) { os << '['; std::copy(a.begin(), a.end(), std::ostream_iterator<typename T::value_type>(os, ", ")); os << ']'; return os; } 

I know that this is far from ideal (constructive comments appreciated), but the problem I came across is that it works fine for vector, deque and list, but not suitable for sets, I don't know why, since sets still have iterator interfaces start and end.

Thanks.

EDIT: checked on g ++ (GCC) 4.6.2 2012012 version clang 3.0

EDIT2: I got the job using decltype, but this is not optimal, because now I can not say that it does what I expect (return an iterator).

I don’t know exactly what a set is, first of all, maybe if someone has a way to debug TMP, that would be good.

+2
source share
2 answers

Since std::set<T> has only one set of immutable iterators, there is only one version of begin() and end() declared as const . That is, the definition of std::set<T> looks something like this (assuming it was previously declared in the std ):

 template <typename T> class std::set { public: class iterator; typedef iterator const_iterator; ... const_iterator begin() const; const_iterator end() const; ... }; 

Other containers have both const and non const versions of begin() and end() corresponding to the signature you are asking for. std::set does not have this. I'm not sure what might be easiest for this.

However, sizeof(char) allowed to be sizeof(long) . The easiest way to ensure that the types yes and no are of different sizes is to use references to arrays of different sizes for the same type, for example:

 typedef char (&yes)[1]; typedef char (&no)[2]; ... enum { value = sizeof(some_expression) == sizeof(yes) }; 
+4
source

It works for vector , but not for set , because the latter returns const_iterator for the begin / end functions. Change:

 typename T::iterator(T::*)(), 

in

 typename T::const_iterator(T::*)() const, 
+2
source

Source: https://habr.com/ru/post/920871/


All Articles