Boost logo

Boost :

From: Peder Holt (peder.holt_at_[hidden])
Date: 2006-10-20 14:43:56


We have recently been working to implement support for deduction of
stl iterators in the typeof emulation. In the process, a method to
completely deduce the type of nested templates emerged.

Initially we want to make this method available in order to deduce
dinkumware iterators, as there is no (standard) way to do that at
present. With the method we are able to deduce e.g.
std::set<UserType,user_predicate<UserType>,user_allocator<UserType>
>::const_iterator, given separate registration of the template
user_predicate and user_allocator.

It is possible to envision a general utility for registering template
nested classes with the typeof emulation. Is there any interest in
this? Otherwise we'll only add specialized code for stl iterators.

The method consists of two steps. The first of which is well known.
Given a type T (presumably an iterator)
Lets assume it is of type std::set<T,std::greater<T> >::iterator
1. Check if it has a value_type typedef, using enable_if.
2. If it has a value_type typedef, pass the value_type to a predicate
resolver (enabled with enable_if IFF the resulting iterator generated
using that predicate matches T).
3. The predicate resolver sends the value_type on to the allocator
resolver which uses enable_if in the same way. The allocator resolver
in turn tries to match against an actual iterator, using the given
value_type, predicate and allocator.
Below is a sample code: deduction of allocator type is ignored for simplicity.

template<class T>
static char has_value_type_helper(typename T::value_type*);

template<class T>
static char (&has_value_type_helper(...))[2];

template<class T>
struct has_value_type
    : boost::mpl::bool_<sizeof(has_value_type_helper<T>(0)) == sizeof(char)>
{};

template<typename T,typename ValueType,typename Pred,typename Enable=void>
struct deduce_set : boost::mpl::false_ {};

template<typename T,typename ValueType,typename Enable=void>
struct deduce_set_predicate : boost::mpl::false_ {};

template<typename T,typename Enable=void>
struct is_set_iterator : boost::mpl::false_ {};

template<typename T,typename ValueType,typename Pred>
struct deduce_set<T,ValueType,Pred,typename
boost::enable_if<boost::is_same<T,typename
std::set<ValueType,Pred>::iterator> >::type>
: boost::mpl::true_
{
    typedef std::set<ValueType,Pred> container_type;
    BOOST_STATIC_CONSTANT(bool,is_const_iterator=false);
};

template<typename T,typename ValueType,typename Pred>
struct deduce_set<T,ValueType,Pred,typename
boost::enable_if<boost::is_same<T,typename
std::set<ValueType,Pred>::const_iterator> >::type>
    : boost::mpl::true_
{
    typedef std::set<ValueType,Pred> container_type;
    BOOST_STATIC_CONSTANT(bool,is_const_iterator=true);
};

/*Enable this template only if std::set<ValueType,std::less<ValueType>
>::(const_)iterator is the same type as T */

template<typename T,typename ValueType>
struct deduce_set_predicate<T,ValueType,typename
boost::enable_if<deduce_set<T,ValueType,std::less<ValueType> >
>::type> :
deduce_set<T,ValueType,std::less<ValueType> >
{};

/*Enable this template only if
std::set<ValueType,std::greater<ValueType> >::(const_)iterator is the
same type as T */
template<typename T,typename ValueType>
struct deduce_set_predicate<T,ValueType,typename
boost::enable_if<deduce_set<T,ValueType,std::greater<ValueType> >
>::type> :
deduce_set<T,ValueType,std::greater<ValueType> >
{};

//Check if type has value_type typedef
template<typename T>
struct is_set_iterator<T,typename boost::enable_if<has_value_type<T> >::type >
: deduce_set_predicate<T,typename T::value_type>
{};

int main()
{
    bool value=is_set_iterator<std::set<int, std::greater<int>
>::iterator>::value;
    typedef is_set_iterator<std::set<int, std::greater<int>
>::iterator>::container_type container_type;
    typedef is_set_iterator<int>::container_type container_type;
//Fails to compile
    return 0;
}

Regards,
Peder


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk