
Hello, I've had much use of a small traits class for identifying types that matches the STL Container concept (roughly) . Two functions is made available, is_container<T> and container_category_of<T>. is_container simply evaluates to true_type or false_type, container_category_of tries to categorize T with the following tags. struct non_container_tag {}; struct container_tag {}; struct sequence_container_tag : public container_tag {}; struct associative_container_tag : public container_tag {}; struct hashed_container_tag : public associative_container_tag {}; template<class T, class Tag = container_tag> struct is_container It seems to work for STL containers, boost multi index, boost array etc.. haven't tried with ptr_containers yet but they should work, since the implementation just looks for a couple of member types using BOOST_MPL_HAS_XXX_TRAIT_DEF. Writing stream operators for a container can be implemented like template<class CharType, class CharTrait, class Container> inline typename boost::enable_if<is_container<Container>, basic_ostream<CharType, CharTrait>&>::type operator <<(basic_ostream<CharType, CharTrait>& os, const Container& c) { if (!os.good() ) return os; detail::write_container(os, c, d); return os; } Writing a generic insert() could look something like namespace detail { template<class Container, class T> bool insert(Container& c, const T& t, sequence_container_tag) { c.push_back(t); return true; } template<class Container, class T> bool insert(Container& c, const T& t, associative_container_tag) { return c.insert(t).second; } } template<class Container, class T> bool insert(Container& c, const T& t) { return detail::insert(c, t, container_category_of<Container>::type()); } Could this be of any use in boost? / Christian

Christian Holmquist wrote:
Hello,
I've had much use of a small traits class for identifying types that matches the STL Container concept (roughly) . Two functions is made available, is_container<T> and container_category_of<T>.
is_container simply evaluates to true_type or false_type, container_category_of tries to categorize T with the following tags.
struct non_container_tag {}; struct container_tag {}; struct sequence_container_tag : public container_tag {}; struct associative_container_tag : public container_tag {}; struct hashed_container_tag : public associative_container_tag {};
template<class T, class Tag = container_tag> struct is_container
It must be useful. It could be more useful if it supports 'is_std_pair' and 'is_std_vector' etc. Also, <std_pair_fwd.hpp> and <std_vector_fwd.hpp> etc could be useful. -- Shunsuke Sogame

It must be useful. It could be more useful if it supports 'is_std_pair' and 'is_std_vector' etc. Also, <std_pair_fwd.hpp> and <std_vector_fwd.hpp> etc could be useful.
My first attempt was implemented this way, by simply forward declaring std containers: namespace std { template<class T, class Alloc> class vector; } template<class T, class Alloc> struct is_container< std::vector<T, Alloc> > : public boost::true_type { typedef sequence_tag container_category; }; This of course didn't scale very well, since it required is_container<> to be manually specialized for every container class. I needed something that worked automatically, so I decided for the following implementation.. Do you think it would be better to forward declare classes instead? (i.e., multi_index, ptr_container, array etc..) #ifndef TT_CONTAINER_TRAITS_HPP_INCLUDED #define TT_CONTAINER_TRAITS_HPP_INCLUDED #include <boost/type_traits/config.hpp> #include <boost/mpl/has_xxx.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits/detail/bool_trait_def.hpp> namespace container_traits { struct non_container_tag {}; struct container_tag {}; struct sequence_container_tag : public container_tag {}; struct associative_container_tag : public container_tag {}; struct hashed_container_tag : public associative_container_tag {}; template<class T, class Tag = container_tag> struct is_container; namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type); BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator); BOOST_MPL_HAS_XXX_TRAIT_DEF(size_type); BOOST_MPL_HAS_XXX_TRAIT_DEF(reference); BOOST_MPL_HAS_XXX_TRAIT_DEF(key_type); BOOST_MPL_HAS_XXX_TRAIT_DEF(hasher); BOOST_TT_AUX_BOOL_TRAIT_DEF1( has_container_traits, T, has_value_type<T>::value & has_iterator<T>::value & has_size_type<T>::value & has_reference<T>::value) } BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_1( class T, is_container, T, container_tag, detail::has_container_traits<T>::value) BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_1( class T, is_container, T, sequence_container_tag, detail::has_container_traits<T>::value &!detail::has_key_type<T>::value) BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_1( class T, is_container, T, associative_container_tag, detail::has_container_traits<T>::value &detail::has_key_type<T>::value) BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_1( class T, is_container, T, hashed_container_tag, detail::has_container_traits<T>::value &detail::has_key_type<T>::value &detail::has_hasher<T>::value) #include <boost/type_traits/detail/bool_trait_undef.hpp> template<class T> struct container_category_of { typedef typename boost::mpl::if_ < detail::has_container_traits<T>, typename boost::mpl::if_ < detail::has_key_type<T>, typename boost::mpl::if_ < detail::has_hasher<T>, hashed_container_tag, associative_container_tag >::type, sequence_container_tag >::type, non_container_tag >::type type; }; } #endif On 14/05/07, shunsuke <pstade.mb@gmail.com > wrote:
Christian Holmquist wrote:
Hello,
I've had much use of a small traits class for identifying types that matches the STL Container concept (roughly) . Two functions is made available, is_container<T> and container_category_of<T>.
is_container simply evaluates to true_type or false_type, container_category_of tries to categorize T with the following tags.
struct non_container_tag {}; struct container_tag {}; struct sequence_container_tag : public container_tag {}; struct associative_container_tag : public container_tag {}; struct hashed_container_tag : public associative_container_tag {};
template<class T, class Tag = container_tag> struct is_container
It must be useful. It could be more useful if it supports 'is_std_pair' and 'is_std_vector' etc. Also, <std_pair_fwd.hpp> and <std_vector_fwd.hpp> etc could be useful.
-- Shunsuke Sogame
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist wrote:
It must be useful. It could be more useful if it supports 'is_std_pair' and 'is_std_vector' etc. Also, <std_pair_fwd.hpp> and <std_vector_fwd.hpp> etc could be useful.
My first attempt was implemented this way, by simply forward declaring std containers:
namespace std { template<class T, class Alloc> class vector; }
template<class T, class Alloc> struct is_container< std::vector<T, Alloc> > : public boost::true_type { typedef sequence_tag container_category; };
This of course didn't scale very well, since it required is_container<> to be manually specialized for every container class. I needed something that worked automatically, so I decided for the following implementation.. Do you think it would be better to forward declare classes instead? (i.e., multi_index, ptr_container, array etc..)
The has_xxx way may return a superset. For example, 'boost::iterator_range' might be wrongly identified as container, and a program might be ill-formed. So it may have little choice but to return a subset, IMO. IIRC, a forward declaration of standard container is, strictly speaking, not allowed. Also, vector is allowed to have extra template parameters. A portable layer to bell a cat can be valuable. Regards, -- Shunsuke Sogame

The has_xxx way may return a superset. For example, 'boost::iterator_range' might be wrongly identified as container, and a program might be ill-formed. So it may have little choice but to return a subset, IMO.
IIRC, a forward declaration of standard container is, strictly speaking, not allowed. Also, vector is allowed to have extra template parameters.
Understood. So, would a more correct implementation of is_container forward declare STL containers in a portable way and specialize the traits class for each one? I'm working with STLport and VC 7.1/8.0 so I can have the forward declarations working for these, but I don't know about other stl implementations. Thanks a lot for your input. On 14/05/07, shunsuke <pstade.mb@gmail.com> wrote:
Christian Holmquist wrote:
It must be useful. It could be more useful if it supports 'is_std_pair' and 'is_std_vector' etc. Also, <std_pair_fwd.hpp> and <std_vector_fwd.hpp> etc could be useful.
My first attempt was implemented this way, by simply forward declaring std containers:
namespace std { template<class T, class Alloc> class vector; }
template<class T, class Alloc> struct is_container< std::vector<T, Alloc> > : public boost::true_type { typedef sequence_tag container_category; };
This of course didn't scale very well, since it required is_container<> to be manually specialized for every container class. I needed something that worked automatically, so I decided for the following implementation.. Do you think it would be better to forward declare classes instead? (i.e ., multi_index, ptr_container, array etc..)
The has_xxx way may return a superset. For example, 'boost::iterator_range' might be wrongly identified as container, and a program might be ill-formed. So it may have little choice but to return a subset, IMO.
IIRC, a forward declaration of standard container is, strictly speaking, not allowed. Also, vector is allowed to have extra template parameters. A portable layer to bell a cat can be valuable.
Regards,
-- Shunsuke Sogame
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist wrote:
So, would a more correct implementation of is_container forward declare STL containers in a portable way and specialize the traits class for each one?
That seems reasonable.
I'm working with STLport and VC 7.1/8.0 so I can have the forward declarations working for these, but I don't know about other stl implementations.
<boost/lambda/detail/operator_return_type_traits.hpp> has some forward declarations. libstdc++ debug mode would be trouble? Regards, -- Shunsuke Sogame

<boost/lambda/detail/operator_return_type_traits.hpp>has some forward declarations. <libstdc++ debug mode would be trouble? I found more forward declarations in boost/functional/detail/container_fwd.hpp, and this one seems to get the job done. Maybe this file could be moved into boost/detail/ instead? Besides, it seems to me that boost/functional/hash could be one possible client of a is_container function, but I haven't looked very closely though so I could be mistaken. Regards, On 23/05/07, shunsuke <pstade.mb@gmail.com> wrote:
Christian Holmquist wrote:
So, would a more correct implementation of is_container forward declare STL containers in a portable way and specialize the traits class for each one?
That seems reasonable.
I'm working with STLport and VC 7.1/8.0 so I can have the forward declarations working for these, but I don't know about other stl implementations.
<boost/lambda/detail/operator_return_type_traits.hpp> has some forward declarations. libstdc++ debug mode would be trouble?
Regards,
-- Shunsuke Sogame
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist wrote:
<boost/lambda/detail/operator_return_type_traits.hpp>has some forward declarations. <libstdc++ debug mode would be trouble?
I found more forward declarations in boost/functional/detail/container_fwd.hpp, and this one seems to get the job done.
Wow, I love that header! Well, container_traits is the former name of Boost.Range. Regards, -- Shunsuke Sogame

Wow, I love that header!
boost/functional/detail/container_fwd.hpp doesn't handle hash_set/map though. STL shipped with VC 7.1 and 8.0 put these containers into namespace stdext, and they have one less template parameter as well. The following forwarding works for VC with and without stlport #if defined(_STDEXT) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) #define USE_STDEXT namespace stdext { template<class Key, class HashCompare, class Allocator> class hash_set; template<class Key, class HashCompare, class Allocator> class hash_multiset; template<class Key, class T, class HashCompare, class Allocator> class hash_map; template<class Key, class T, class HashCompare, class Allocator> class hash_multimap; } #else namespace std { template<class Key, class Hash, class Compare, class Allocator> class hash_set; template<class Key, class Hash, class Compare, class Allocator> class hash_multiset; template<class Key, class T, class Hash, class Compare, class Allocator> class hash_map; template<class Key, class T, class Hash, class Compare, class Allocator> class hash_multimap; } #endif Do you know how hash_map/set look on other platforms? Do they differ from stlport? Regards, On 24/05/07, shunsuke <pstade.mb@gmail.com> wrote:
Christian Holmquist wrote:
<boost/lambda/detail/operator_return_type_traits.hpp>has some forward declarations. <libstdc++ debug mode would be trouble?
I found more forward declarations in boost/functional/detail/container_fwd.hpp, and this one seems to get the job done.
Wow, I love that header!
Well, container_traits is the former name of Boost.Range.
Regards,
-- Shunsuke Sogame
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On May 10, 2007, at 6:56 AM, Christian Holmquist wrote:
I've had much use of a small traits class for identifying types that matches the STL Container concept (roughly) .
May I ask why, or in what situation? I am reminded of Item 2 of Meyers "Beware the Illusion of Container-Independent Code". . -- Hervé Brönnimann CIS, Polytechnic University

May I ask why, or in what situation? I am reminded of Item 2 of Meyers "Beware the Illusion of Container-Independent Code". . --
I posted a trivial examle of writing a generic output stream operator for all container types.. It works for all containers given that their value_type also implements the stream operator. To me it is (was) an occuring task to overload container types, since I usually want algorithms or components to work out-of-the-box with containers. If I put some requirements on type T for my algorithm A, and I can express how A should behave if T is a container, then T::value_type must fulfill the requirement and I can specialize the the algorithm for this case. Mostly I provide specializations for boost::variant and boost::fusion sequences, but STL contains a too big set of containers to specialize each and every one. Does it make any sense? Regards, Christian On 15/05/07, Hervé Brönnimann <hervebronnimann@mac.com> wrote:
On May 10, 2007, at 6:56 AM, Christian Holmquist wrote:
I've had much use of a small traits class for identifying types that matches the STL Container concept (roughly) .
May I ask why, or in what situation? I am reminded of Item 2 of Meyers "Beware the Illusion of Container-Independent Code". . -- Hervé Brönnimann CIS, Polytechnic University _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist skrev:
May I ask why, or in what situation? I am reminded of Item 2 of Meyers "Beware the Illusion of Container-Independent Code". . --
I posted a trivial examle of writing a generic output stream operator for all container types.. It works for all containers given that their value_type also implements the stream operator. To me it is (was) an occuring task to overload container types, since I usually want algorithms or components to work out-of-the-box with containers. If I put some requirements on type T for my algorithm A, and I can express how A should behave if T is a container, then T::value_type must fulfill the requirement and I can specialize the the algorithm for this case. Mostly I provide specializations for boost::variant and boost::fusion sequences, but STL contains a too big set of containers to specialize each and every one.
Does it make any sense?
Yes and no. Container traits could be useful with container operations like insert, not for outputting a range of values (Boost.Range is more generic here). -Thorsten

Yes and no. Container traits could be useful with container operations like insert, not for outputting a range of values (Boost.Range is more generic here).
Can I determine from a type T if it is a range, or if I can construct a range from it? I remember looking for something like this but couldn't find it. On 24/05/07, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
May I ask why, or in what situation? I am reminded of Item 2 of Meyers "Beware the Illusion of Container-Independent Code". . --
I posted a trivial examle of writing a generic output stream operator for all container types.. It works for all containers given that their value_type also implements the stream operator. To me it is (was) an occuring task to overload container types, since I usually want algorithms or components to work out-of-the-box with containers. If I put some requirements on type T for my algorithm A, and I can express how A should behave if T is a container, then T::value_type must fulfill
Christian Holmquist skrev: the
requirement and I can specialize the the algorithm for this case. Mostly I provide specializations for boost::variant and boost::fusion sequences, but STL contains a too big set of containers to specialize each and every one.
Does it make any sense?
Yes and no. Container traits could be useful with container operations like insert, not for outputting a range of values (Boost.Range is more generic here).
-Thorsten _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist skrev:
Yes and no. Container traits could be useful with container operations like insert, not for outputting a range of values (Boost.Range is more generic here).
Can I determine from a type T if it is a range, or if I can construct a range from it? I remember looking for something like this but couldn't find it.
There is no is_range<T>::value trait. So no. Is that needed for output? -Thorsten

There is no is_range<T>::value trait. So no. Is that needed for output?
Well, if I have a boost::tuple<std::vector<int> >, how would I output that using the stream operators of boost::tuple? or boost::variant, or fusion sequences, etc.. With container traits I get both input and output for free here. On 24/05/07, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
Christian Holmquist skrev:
Yes and no. Container traits could be useful with container operations like insert, not for outputting a range of values (Boost.Range is more generic here).
Can I determine from a type T if it is a range, or if I can construct a range from it? I remember looking for something like this but couldn't find it.
There is no is_range<T>::value trait. So no.
Is that needed for output?
-Thorsten _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Christian Holmquist skrev:
There is no is_range<T>::value trait. So no. Is that needed for output?
Well, if I have a boost::tuple<std::vector<int> >, how would I output that using the stream operators of boost::tuple? or boost::variant, or fusion sequences, etc..
With container traits I get both input and output for free here.
OK, although I'm a bit confused: boost::tuple<> is not a container in the normal sense. So what has this got to do with container traits? -Thorsten

OK, although I'm a bit confused: boost::tuple<> is not a container in the normal sense. So what has this got to do with container traits?
How would one control the output mechanism of boost::tuple using boost range? Boost range doesn't help much when it comes to outputting something like tuple<std::vector<T> >, since the global operator<< can't be invoked for vector<T>. Working with containers, not only ranges, is such a common task that it shouldn't require twenty or so overloads to describe one function. Boost Range is indeed helpful and I use it a lot, but I don't think its existence makes container_traits useless. / Christian On 24/05/07, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
There is no is_range<T>::value trait. So no. Is that needed for output?
Well, if I have a boost::tuple<std::vector<int> >, how would I output
Christian Holmquist skrev: that
using the stream operators of boost::tuple? or boost::variant, or fusion sequences, etc..
With container traits I get both input and output for free here.
OK, although I'm a bit confused: boost::tuple<> is not a container in the normal sense. So what has this got to do with container traits?
-Thorsten _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (4)
-
Christian Holmquist
-
Hervé Brönnimann
-
shunsuke
-
Thorsten Ottosen