typetraits of STL containers and iterators

L

laikon

dear all:
how to discriminate STL containers from iterators by their typetraits.
the typetraits in boost don't seem to work.

If I want to define some traits, such as is_container or is_iterator,
how should I do?
 
S

sebastian

I've never used boost::type_traits personally, but I would think it
would work. Not sure though. If not, you could define a template and
then specialize accordingly. I gave it a try, thinking most STL
iterators would be derived from std::iterator:

#include <iterator>

template < typename Type >
struct is_iterator_type
{
enum { value = false };
};

template < class Category, class Type, class Distance, class Pointer,
class Reference >
struct is_iterator_type< std::iterator< Category, Type, Distance,
Pointer, Reference > >
{
enum { value = true };
};

template < typename Type >
struct is_iterator_type< Type* >
{
enum { value = true };
};

template < typename Type >
struct is_iterator_type< Type const* >
{
enum { value = true };
};

/*
Helper function that deduces the type of some value
*/
template < typename Type >
inline bool is_iterator( Type const& )
{
return is_iterator_type< Type >::value;
}

// Test:

#include <cassert>
#include <list>
#include <vector>

int main( void )
{
using namespace
std;
char*
pc = 0;
char const*
pcc = 0;
char const* const
pccc = 0;
list< char >
lc;
vector< char >
vc;
assert( is_iterator( pc ) );
assert( is_iterator( pcc ) );
assert( is_iterator( pccc ) );
assert( is_iterator( lc.begin( ) ) );
assert( is_iterator( vc.rbegin( ) ) );
return 0;
}

Unfortunately, the assertion failed on the container iterators. So you
would need to specialize is_iterator_type for every possibility. And
as far as detected a container type, again, neither do these have a
common base class, so you would have to define and specialize a
template for every know type.

- hth
 
M

Michael Doubez

I've never used boost::type_traits personally, but I would think it
would work. Not sure though. If not, you could define a template and
then specialize accordingly. I gave it a try, thinking most STL
iterators would be derived from std::iterator:

#include <iterator>

template < typename Type >
struct is_iterator_type
{
        enum { value = false };

};

template < class Category, class Type, class Distance, class Pointer,
class Reference >
struct is_iterator_type< std::iterator< Category, Type, Distance,
Pointer, Reference > >
{
        enum { value = true };

};

template < typename Type >
struct is_iterator_type< Type* >
{
        enum { value = true };

};

template < typename Type >
struct is_iterator_type< Type const* >
{
        enum { value = true };

};

/*
        Helper function that deduces the type of some value
*/
template < typename Type >
inline bool is_iterator( Type const& )
{
        return is_iterator_type< Type >::value;

}
/.. [snip]
Unfortunately, the assertion failed on the container iterators. So you
would need to specialize is_iterator_type for every possibility. And
as far as detected a container type, again, neither do these have a
common base class, so you would have to define and specialize a
template for every know type.


This seems a bit complicated, it is easier using SFINAE on
type_trait<T>::iterator_category.


template<typename T>
class is_iterator{
private:
typedef char hasItTrait;
typedef struct { char a[2]; } hasNotItTrait;

static hasItTrait test( int ,
std::type_trait<T>::iterator_category=std::type_trait<T>::iterator_category
());
static HasNotItTrait test(...);

public:
static const bool value = sizeof(is_iterator<T>::test(0)) == sizeof
(hasItTrait);
};

Not tested but it should work well enough.
 
M

Michael Doubez

I've never used boost::type_traits personally, but I would think it
would work. Not sure though. If not, you could define a template and
then specialize accordingly. I gave it a try, thinking most STL
iterators would be derived from std::iterator:
#include <iterator>
template < typename Type >
struct is_iterator_type
{
        enum { value = false };

template < class Category, class Type, class Distance, class Pointer,
class Reference >
struct is_iterator_type< std::iterator< Category, Type, Distance,
Pointer, Reference > >
{
        enum { value = true };

template < typename Type >
struct is_iterator_type< Type* >
{
        enum { value = true };

template < typename Type >
struct is_iterator_type< Type const* >
{
        enum { value = true };

/*
        Helper function that deduces the type of some value
*/
template < typename Type >
inline bool is_iterator( Type const& )
{
        return is_iterator_type< Type >::value;

/.. [snip]
Unfortunately, the assertion failed on the container iterators. So you
would need to specialize is_iterator_type for every possibility. And
as far as detected a container type, again, neither do these have a
common base class, so you would have to define and specialize a
template for every know type.

This seems a bit complicated, it is easier using SFINAE on
type_trait<T>::iterator_category.

I mean std::iterator_traits said:
template<typename T>
class is_iterator{
  private:
    typedef char hasItTrait;
    typedef struct { char a[2]; } hasNotItTrait;

    static hasItTrait test( int ,
std::iterator_traits<T>::iterator_category=std::iterator_traits<T>::iterator_category
());
    static HasNotItTrait test(...);

  public:
    static const bool value = sizeof(is_iterator<T>::test(0)) == sizeof
(hasItTrait);

};

Not tested but it should work well enough.
 
S

sebastian

Sorry, Micheal, I'm just not getting your example. How exactly is it
supposed to work, now? What does the test function actually do?
 
S

sebastian

Michael, after staring at your code for a while it finally occured to
me what you were getting at (except for the padded struct bit). Quite
ingenious, actually. So I put together something I thought should
work, and indeed it does detect iterators perfectly. Unfortunately,
gcc appears not to be handling SFINAE correctly, and when I pass along
a non-iterator I get an error! Am I doing something wrong here?

#include <iterator>

template < typename Type >
struct is_iterator_type
{
static bool const
value;

private:

static bool test
(
int,
typename std::iterator_traits< Type >::iterator_category =
typename std::iterator_traits< Type >::iterator_category( )
)
{
return true;
}

static bool test( ... )
{
return false;
}
};

template < typename Type >
bool const
is_iterator_type< Type >::value = is_iterator_type< Type >::test
( 0 );

/*
Helper function that deduces the type of some value
*/
template < typename Type >
inline bool is_iterator( Type const& )
{
return is_iterator_type< Type >::value;

}

// test:

#include <cassert>
#include <list>
#include <vector>

struct not_an_iterator
{ };

int main( void )
{
using namespace
std;

not_an_iterator
nai;
char*
pc = 0;
char const*
pcc = 0;
char const* const
pccc = 0;
list< char >
lc;
vector< char >
vc;
assert( is_iterator( pc ) );
assert( is_iterator( pcc ) );
assert( is_iterator( pccc ) );
assert( is_iterator( lc.begin( ) ) );
assert( is_iterator( vc.rbegin( ) ) );
assert( !is_iterator( nai ) );
return 0;
}

I'm using mingw gcc 4.4.0, by the way.
 
M

Michael Doubez

Michael, after staring at your code for a while it finally occured to
me what you were getting at (except for the padded struct bit). Quite
ingenious, actually. So I put together something I thought should
work, and indeed it does detect iterators perfectly. Unfortunately,
gcc appears not to be handling SFINAE correctly, and when I pass along
a non-iterator I get an error! Am I doing something wrong here?
[snip]

No. I could not get a working example either.
This is due to the std::iterator_traits<> specialisation indirection.

I don't know how to check with MPL if a specialisation of a template
does exists. Perhaps worth a question on comp.lang.c++.moderated or on
boost mailing list.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top