|
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