Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2000-01-16 14:20:55


John Maddock wrote on 1/16/2000 7:39 AM
>Steve, Howard, Beman,
>
>I've had a chance to take a closer look at Steve's updated type_traits
>code, and I think on reflection I'm pretty happy with it, I've made some
>minor changes and loaded them to the document vault
>(http://www.egroups.com/docvault/boost/TypeTraits/version3?null=1) as
>type_traits.hpp and type_traits_regress.cpp, along with some usage examples
>in algo_opt_examples.cpp (more on that in a separate thread).
>
>The main changes are:
>
>1) changed the header file name to type_traits.hpp - I've found mixed case
>filenames to be a real pain in past - having said that you can call it
>whatever you like :-)

Quick survey of current header names in boost reveals no capital letters
used.

>5) I've added code for call_traits based on type_traits - maybe this should
>be in utility.hpp rather than here? Howard do you have compressed_pair
>ready to go based on type_traits?

Yup. What header do we want it in? (code included below to get review
started)

>I have some remaining issues/questions:
>
>1) Steve, do you feel strongly about having both is_xxx and is_builtin_xxx
>families - the reason I ask is that templates like is_integral duplicate
>exactly the functionality already available from numeric_limits - removing
>these would allow us to remove the dependency on <limits> also.
>
>2) The is_fundamental versions make no sense to me, maybe I'm looking at
>this wrong but a type is either fundamental or not - equivalent to your
>is_standard_fundamental I think.
>
>3) Howard - Steve's code does not "work" with cv-qualified types for
>templates like is_integral<>, IMO this is the right way, but if you feel
>really strongly the other way, make the change and I won't argue - Steve
>what do you think?

I feel most strongly that it is time to move forward with type_traits.
If I am the only one that does not like:

is_pointer<int*const>::value -> false
is_integral<const int>::value -> false

then it is not worth further debate.

I also still feel that numeric_limits should not be involved at all here,
but again, it is time to move forward.

Minor comments and proposed changes:

I had to modify empty_helper_t1 to work around a Metrowerks compiler bug:

template <typename T>
struct empty_helper_t1 : public T
{
#ifdef __MWERKS__
        empty_helper_t1(); // hh compiler bug workaround
#endif
        int i[256];
};

A ';' got loose here:

template <typename T>
struct empty_helper<T, true>
{
   static const bool value = (sizeof(empty_helper_t1<T>) ==
sizeof(empty_helper_t2));
};
} // hh deleted ';'

In call_traits:

template <typename T>
struct call_traits<T&>
{
   typedef T& value_type;
   typedef T& reference;
   typedef const T& const_reference;
   typedef T& param_type; // hh removed const
};

I think references should be passed by non-const reference. This
behavior can be very important in the selection of viable methods
(thinking auto_ptr here).

Also I completely clobbered your call_traits<array> :-) But on shakey
ground so I would appreciate some feedback.

template <typename T, std::size_t N>
struct call_traits<T [N]>
{
   typedef const T* value_type; // hh was typedef T
value_type[N];
   typedef T(&reference)[N]; // hh was typedef T*& reference;
   typedef const T(&const_reference)[N]; // hh was typedef const T*&
const_reference;
   typedef const value_type param_type; // hh was typedef T* param_type;
};

My thinking was guided by:

1. Trying to implement Dietmar's solution for make_pair which was first
presented to me as:

#include <utility>
#include <string>

template <typename T>
struct reference_traits
{
        typedef T value_type;
};

template <typename T, unsigned long sz>
struct reference_traits<T[sz]>
{
        typedef T const* value_type;
};

template <typename S, typename T>
std::pair<typename reference_traits<S>::value_type, typename
reference_traits<T>::value_type>
make_pair(const S& s, const T& t)
{
        return std::pair<typename reference_traits<S>::value_type, typename
reference_traits<T>::value_type>(s, t);
}

int main()
{
        std::pair<const std::string, int> a(make_pair("abc", 123));
}

2. Trying to implement a "generic" use:

template <typename T> class A;

template <typename T, std::size_t sz>
class A<T[sz]>
{
public:
        typedef typename call_traits<T[sz]>::value_type value_type;
        typedef typename call_traits<T[sz]>::reference reference;
        typedef typename call_traits<T[sz]>::const_reference const_reference;
        typedef typename call_traits<T[sz]>::param_type param_type;
        A(param_type data) {std::memcpy(data_, data, sz*sizeof(T));}
        value_type return_by_value() const {return data_;}
        reference return_by_reference() {return data_;}
        const_reference return_by_const_reference() const {return data_;}
private:
        T data_[sz];
};

int main()
{
                typedef char Char4[4];
                Char4 i = "abc";
                std::cout << "i = " << i << '\n';
                A<Char4> a1(i);
                Char4& i1 = a1.return_by_reference();
                std::strcpy(i1, "def");
                std::cout << "i = " << i << '\n';
                std::cout << "i1 = " << i1 << '\n';
                const Char4& i2 = a1.return_by_const_reference();
                std::cout << "i2 = " << i2 << '\n';
                Char4 i3;
                std::strcpy(i3, a1.return_by_value());
                std::cout << "i3 = " << i3 << '\n';
}

In type_traits_regress.cpp a few minor changes as well:

   type_test(const int, call_traits<int>::param_type) // hh added const
   type_test(const char, call_traits<char>::param_type) // hh added const
   type_test(char&, call_traits<char&>::param_type) // hh removed
const
   type_test(const char&, call_traits<const char&>::param_type) // hh
added const

Here is what compressed_pair is looking like:

namespace boost
{

// compressed_pair

template <class T1, class T2,
          bool FirstEmpty = is_empty<T1>::value,
          bool SecondEmpty = is_empty<T2>::value> class compressed_pair;

template <class T1, class T2, bool FirstEmpty>
class compressed_pair<T1, T2, FirstEmpty, true>
        : private T2
{
public:
        typedef T1 first_type;
        typedef T2 second_type;
        typedef typename call_traits<first_type>::param_type
first_param_type;
        typedef typename call_traits<second_type>::param_type
second_param_type;
        typedef typename call_traits<first_type>::reference
first_reference;
        typedef typename call_traits<second_type>::reference
second_reference;
        typedef typename call_traits<first_type>::const_reference
first_const_reference;
        typedef typename call_traits<second_type>::const_reference
second_const_reference;

        compressed_pair() {}

        compressed_pair(first_param_type x, second_param_type y)
                : first_(x), second_type(y) {}

        explicit compressed_pair(first_param_type x)
                : first_(x) {}

        explicit compressed_pair(second_param_type y)
                : second_type(y) {}

        first_reference first() {return first_;}
        first_const_reference first() const {return first_;}

        second_reference second() {return *this;}
        second_const_reference second() const {return *this;}

        void swap(compressed_pair& y) {boost::swap(*this, y);}
private:
        first_type first_;
};

template <class T1, class T2, bool FirstEmpty>
inline
void
swap(compressed_pair<T1, T2, FirstEmpty, true>& x, compressed_pair<T1,
T2, FirstEmpty, true>& y)
{
        using std::swap;
        swap(x.first(), y.first());
}

template <class T1, class T2>
class compressed_pair<T1, T2, true, false>
        : private T1
{
public:
        typedef T1 first_type;
        typedef T2 second_type;
        typedef typename call_traits<first_type>::param_type
first_param_type;
        typedef typename call_traits<second_type>::param_type
second_param_type;
        typedef typename call_traits<first_type>::reference
first_reference;
        typedef typename call_traits<second_type>::reference
second_reference;
        typedef typename call_traits<first_type>::const_reference
first_const_reference;
        typedef typename call_traits<second_type>::const_reference
second_const_reference;

        compressed_pair() {}

        compressed_pair(first_param_type x, second_param_type y)
                : first_type(x), second_(y) {}

        explicit compressed_pair(first_param_type x)
                : first_type(x) {}

        explicit compressed_pair(second_param_type y)
                : second_(y) {}

        first_reference first() {return *this;}
        first_const_reference first() const {return *this;}

        second_reference second() {return second_;}
        second_const_reference second() const {return second_;}

        void swap(compressed_pair& y) {boost::swap(*this, y);}
private:
        second_type second_;
};

template <class T1, class T2>
inline
void
swap(compressed_pair<T1, T2, true, false>& x, compressed_pair<T1, T2,
true, false>& y)
{
        using std::swap;
        swap(x.second(), y.second());
}

template <class T1, class T2>
class compressed_pair<T1, T2, false, false>
{
public:
        typedef T1 first_type;
        typedef T2 second_type;
        typedef typename call_traits<first_type>::param_type
first_param_type;
        typedef typename call_traits<second_type>::param_type
second_param_type;
        typedef typename call_traits<first_type>::reference
first_reference;
        typedef typename call_traits<second_type>::reference
second_reference;
        typedef typename call_traits<first_type>::const_reference
first_const_reference;
        typedef typename call_traits<second_type>::const_reference
second_const_reference;

        compressed_pair() {}

        compressed_pair(first_param_type x, second_param_type y)
                : first_(x), second_(y) {}

        explicit compressed_pair(first_param_type x)
                : first_(x) {}

        explicit compressed_pair(second_param_type y)
                : second_(y) {}

        first_reference first() {return first_;}
        first_const_reference first() const {return first_;}

        second_reference second() {return second_;}
        second_const_reference second() const {return second_;}

        void swap(compressed_pair& y) {boost::swap(*this, y);}
private:
        first_type first_;
        second_type second_;
};

template <class T1, class T2>
inline
void
swap(compressed_pair<T1, T2, false, false>& x, compressed_pair<T1, T2,
false, false>& y)
{
        using std::swap;
        swap(x.first(), y.first());
        swap(x.second(), y.second());
}

} // namespace boost

-Howard


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