Compare commits

..

2 Commits

Author SHA1 Message Date
59d9feed35 This commit was manufactured by cvs2svn to create tag
'Version_1_27_0'.

[SVN r12749]
2002-02-07 13:33:59 +00:00
1041e8f836 This commit was manufactured by cvs2svn to create branch 'RC_1_27_0'.
[SVN r12739]
2002-02-06 03:32:50 +00:00
8 changed files with 134 additions and 281 deletions

View File

@ -74,14 +74,22 @@ Both <code>tuple_io.hpp</code> and <code>tuple_comparison.hpp</code> include <co
The template parameters specify the types of the tuple elements. The template parameters specify the types of the tuple elements.
The current version supports tuples with 0-10 elements. The current version supports tuples with 0-10 elements.
If necessary, the upper limit can be increased up to, say, a few dozen elements. If necessary, the upper limit can be increased up to, say, a few dozen elements.
The data element can be any C++ type. The data element can be any C++ type, except for a non-reference type
Note that <code>void</code> and plain function types are valid that is not copy constructible from a const qualified reference to that
C++ types, but objects of such types cannot exist. same type. In practice this means, that the element type must be <i>CopyConstructible</i> [C++ Standard 20.1.3]. (To be precise, CopyConstrucible is an unnecessary strong requirement for a valid element type, as the <code>operator&amp;</code> is not used by the library.)
Hence, if a tuple type contains such types as elements, the tuple type </p>
can exist, but not an object of that type.
There are natural limitations for element types that cannot <p>
be be copied, or that are not default constructible (see 'Constructing tuples' Examples of types that are not allowed as tuple elements:
below).
<ul>
<li>classes that do not have a public copy constructor</li>
<li>classes, where the copy constructor takes its argument as a non-const reference (cf. <code>auto_ptr</code>)
<li>arrays</li>
</ul>
Note that a reference to any of these non-copyable types is a valid element
type.
<p> <p>
For example, the following definitions are valid tuple instantiations (<code>A</code>, <code>B</code> and <code>C</code> are some user defined classes): For example, the following definitions are valid tuple instantiations (<code>A</code>, <code>B</code> and <code>C</code> are some user defined classes):
@ -93,6 +101,21 @@ tuple&lt;std::string, std::pair&lt;A, B&gt; &gt;
tuple&lt;A*, tuple&lt;const A*, const B&amp;, C&gt;, bool, void*&gt; tuple&lt;A*, tuple&lt;const A*, const B&amp;, C&gt;, bool, void*&gt;
</code></pre> </code></pre>
<p>
The following code shows some invalid tuple instantiations:
<pre><code>class Y {
Y(const Y&amp;);
public:
Y();
};
tuple&lt;Y&gt; // not allowed, objects of type Y cannot be copied
tuple&lt;char[10]&gt; // not allowed: arrays cannot be copied
</code></pre>
Note however that <code>tuple&lt;Y&amp;&gt;</code> and <code>tuple&lt;char(&)[10]&gt;</code> are valid instantiations.
<h2><a name = "constructing_tuples">Constructing tuples</a></h2> <h2><a name = "constructing_tuples">Constructing tuples</a></h2>
<p> <p>
@ -133,31 +156,6 @@ tuple&lt;const double&amp;&gt;(d+3.14) // ok, but dangerous:
// the element becomes a dangling reference // the element becomes a dangling reference
</code></pre> </code></pre>
<p>Using an initial value for an element that cannot be copied, is a compile
time error:
<pre><code>class Y {
Y(const Y&amp;);
public:
Y();
};
char a[10];
tuple&lt;char[10], Y&gt;(a, Y()); // error, neither arrays nor Y can be copied
tuple&lt;char[10], Y&gt;(); // ok
</code></pre>
Note particularly that the following is perfectly ok:
<code><pre>Y y;
tuple&lt;char(&amp;)[10], Y&amp;&gt;(a, y);
</code></pre>
It is possible to come up with a tuple type that cannot be constructed.
This occurs if an element that cannot be initialized has a lower
index than an element that requires initialization.
For example: <code>tuple&lt;char[10], int&amp;&gt;</code>.
<p>In sum, the tuple construction is semantically just a group of individual elementary constructions. <p>In sum, the tuple construction is semantically just a group of individual elementary constructions.
</p> </p>

View File

@ -23,11 +23,6 @@
// David Abrahams. // David Abrahams.
// Revision history: // Revision history:
// 2002 05 01 Hugo Duncan: Fix for Borland after Jaakko's previous changes
// 2002 04 18 Jaakko: tuple element types can be void or plain function
// types, as long as no object is created.
// Tuple objects can no hold even noncopyable types
// such as arrays.
// 2001 10 22 John Maddock // 2001 10 22 John Maddock
// Fixes for Borland C++ // Fixes for Borland C++
// 2001 08 30 David Abrahams // 2001 08 30 David Abrahams
@ -41,7 +36,6 @@
#include <utility> // needed for the assignment from pair to tuple #include <utility> // needed for the assignment from pair to tuple
#include "boost/type_traits/cv_traits.hpp" #include "boost/type_traits/cv_traits.hpp"
#include "boost/type_traits/function_traits.hpp"
namespace boost { namespace boost {
namespace tuples { namespace tuples {
@ -51,18 +45,7 @@ struct null_type {};
// a helper function to provide a const null_type type temporary // a helper function to provide a const null_type type temporary
namespace detail { namespace detail {
inline const null_type cnull() { return null_type(); } inline const null_type cnull_type() { return null_type(); }
// -- if construct ------------------------------------------------
// Proposed by Krzysztof Czarnecki and Ulrich Eisenecker
template <bool If, class Then, class Else> struct IF { typedef Then RET; };
template <class Then, class Else> struct IF<false, Then, Else> {
typedef Else RET;
};
} // end detail } // end detail
// - cons forward declaration ----------------------------------------------- // - cons forward declaration -----------------------------------------------
@ -100,6 +83,41 @@ namespace detail {
template<class T> template<class T>
class generate_error; class generate_error;
// tuple default argument wrappers ---------------------------------------
// Work for non-reference types, intentionally not for references
template <class T>
struct default_arg {
// Non-class temporaries cannot have qualifiers.
// To prevent f to return for example const int, we remove cv-qualifiers
// from all temporaries.
static typename boost::remove_cv<T>::type f() { return T(); }
};
// This is just to produce a more informative error message
// The code would fail in any case
template<class T, int N>
struct default_arg<T[N]> {
static T* f() {
return generate_error<T[N]>::arrays_are_not_valid_tuple_elements; }
};
template <class T>
struct default_arg<T&> {
static T& f() {
#ifndef __sgi
return generate_error<T>::no_default_values_for_reference_types;
#else
// MIPSpro instantiates functions even when it should not, so
// this technique can not be used for error checking.
// The simple workaround is to just not have this error checking
// with MIPSpro.
static T x;
return x;
#endif
}
};
// - cons getters -------------------------------------------------------- // - cons getters --------------------------------------------------------
// called: get_class<N>::get<RETURN_TYPE>(aTuple) // called: get_class<N>::get<RETURN_TYPE>(aTuple)
@ -167,7 +185,6 @@ template <class T> struct access_traits {
typedef T& non_const_type; typedef T& non_const_type;
typedef const typename boost::remove_cv<T>::type& parameter_type; typedef const typename boost::remove_cv<T>::type& parameter_type;
// used as the tuple constructors parameter types // used as the tuple constructors parameter types
// Rationale: non-reference tuple element types can be cv-qualified. // Rationale: non-reference tuple element types can be cv-qualified.
// It should be possible to initialize such types with temporaries, // It should be possible to initialize such types with temporaries,
@ -183,6 +200,7 @@ template <class T> struct access_traits<T&> {
typedef T& parameter_type; typedef T& parameter_type;
}; };
// get function for non-const cons-lists, returns a reference to the element // get function for non-const cons-lists, returns a reference to the element
template<int N, class HT, class TT> template<int N, class HT, class TT>
@ -213,28 +231,6 @@ get(const cons<HT, TT>& c BOOST_TUPLE_DUMMY_PARM) {
} }
// -- the cons template -------------------------------------------------- // -- the cons template --------------------------------------------------
namespace detail {
// These helper templates wrap void types and plain function types.
// The reationale is to allow one to write tuple types with those types
// as elements, even though it is not possible to instantiate such object.
// E.g: typedef tuple<void> some_type; // ok
// but: some_type x; // fails
template <class T> class non_storeable_type {
non_storeable_type();
};
template <class T> struct wrap_non_storeable_type {
typedef typename IF<
::boost::is_function<T>::value, non_storeable_type<T>, T
>::RET type;
};
template <> struct wrap_non_storeable_type<void> {
typedef non_storeable_type<void> type;
};
} // detail
template <class HT, class TT> template <class HT, class TT>
struct cons { struct cons {
@ -242,33 +238,28 @@ struct cons {
typedef HT head_type; typedef HT head_type;
typedef TT tail_type; typedef TT tail_type;
typedef typename head_type head;
detail::wrap_non_storeable_type<head_type>::type stored_head_type;
stored_head_type head;
tail_type tail; tail_type tail;
typename access_traits<stored_head_type>::non_const_type typename access_traits<head_type>::non_const_type
get_head() { return head; } get_head() { return head; }
typename access_traits<tail_type>::non_const_type typename access_traits<tail_type>::non_const_type
get_tail() { return tail; } get_tail() { return tail; }
typename access_traits<stored_head_type>::const_type typename access_traits<head_type>::const_type
get_head() const { return head; } get_head() const { return head; }
typename access_traits<tail_type>::const_type typename access_traits<tail_type>::const_type
get_tail() const { return tail; } get_tail() const { return tail; }
cons() : head(), tail() {} cons() : head(detail::default_arg<HT>::f()), tail() {}
// cons() : head(detail::default_arg<HT>::f()), tail() {}
// the argument for head is not strictly needed, but it prevents // the argument for head is not strictly needed, but it prevents
// array type elements. This is good, since array type elements // array type elements. This is good, since array type elements
// cannot be supported properly in any case (no assignment, // cannot be supported properly in any case (no assignment,
// copy works only if the tails are exactly the same type, ...) // copy works only if the tails are exactly the same type, ...)
cons(typename access_traits<stored_head_type>::parameter_type h, cons(typename access_traits<head_type>::parameter_type h,
const tail_type& t) const tail_type& t)
: head (h), tail(t) {} : head (h), tail(t) {}
@ -277,18 +268,9 @@ struct cons {
cons( T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, cons( T1& t1, T2& t2, T3& t3, T4& t4, T5& t5,
T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 ) T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 )
: head (t1), : head (t1),
tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull()) tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull_type())
{} {}
template <class T2, class T3, class T4, class T5,
class T6, class T7, class T8, class T9, class T10>
cons( const null_type& t1, T2& t2, T3& t3, T4& t4, T5& t5,
T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 )
: head (),
tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull())
{}
template <class HT2, class TT2> template <class HT2, class TT2>
cons( const cons<HT2, TT2>& u ) : head(u.head), tail(u.tail) {} cons( const cons<HT2, TT2>& u ) : head(u.head), tail(u.tail) {}
@ -333,24 +315,21 @@ struct cons<HT, null_type> {
typedef HT head_type; typedef HT head_type;
typedef null_type tail_type; typedef null_type tail_type;
typedef typename head_type head;
detail::wrap_non_storeable_type<head_type>::type stored_head_type;
stored_head_type head;
typename access_traits<stored_head_type>::non_const_type typename access_traits<head_type>::non_const_type
get_head() { return head; } get_head() { return head; }
null_type get_tail() { return null_type(); } null_type get_tail() { return null_type(); }
typename access_traits<stored_head_type>::const_type typename access_traits<head_type>::const_type
get_head() const { return head; } get_head() const { return head; }
const null_type get_tail() const { return null_type(); } const null_type get_tail() const { return null_type(); }
// cons() : head(detail::default_arg<HT>::f()) {} cons() : head(detail::default_arg<HT>::f()) {}
cons() : head() {}
cons(typename access_traits<stored_head_type>::parameter_type h, cons(typename access_traits<head_type>::parameter_type h,
const null_type& = null_type()) const null_type& = null_type())
: head (h) {} : head (h) {}
@ -360,12 +339,6 @@ struct cons<HT, null_type> {
const null_type&, const null_type&, const null_type&) const null_type&, const null_type&, const null_type&)
: head (t1) {} : head (t1) {}
cons(const null_type& t1,
const null_type&, const null_type&, const null_type&,
const null_type&, const null_type&, const null_type&,
const null_type&, const null_type&, const null_type&)
: head () {}
template <class HT2> template <class HT2>
cons( const cons<HT2, null_type>& u ) : head(u.head) {} cons( const cons<HT2, null_type>& u ) : head(u.head) {}
@ -451,96 +424,30 @@ public:
// access_traits<T>::parameter_type takes non-reference types as const T& // access_traits<T>::parameter_type takes non-reference types as const T&
tuple() {} explicit tuple(
typename access_traits<T0>::parameter_type t0
= detail::default_arg<T0>::f(),
typename access_traits<T1>::parameter_type t1
= detail::default_arg<T1>::f(),
typename access_traits<T2>::parameter_type t2
= detail::default_arg<T2>::f(),
typename access_traits<T3>::parameter_type t3
= detail::default_arg<T3>::f(),
typename access_traits<T4>::parameter_type t4
= detail::default_arg<T4>::f(),
typename access_traits<T5>::parameter_type t5
= detail::default_arg<T5>::f(),
typename access_traits<T6>::parameter_type t6
= detail::default_arg<T6>::f(),
typename access_traits<T7>::parameter_type t7
= detail::default_arg<T7>::f(),
typename access_traits<T8>::parameter_type t8
= detail::default_arg<T8>::f(),
typename access_traits<T9>::parameter_type t9
= detail::default_arg<T9>::f())
tuple(typename access_traits<T0>::parameter_type t0)
: inherited(t0, detail::cnull(), detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1)
: inherited(t0, t1, detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2)
: inherited(t0, t1, t2, detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3)
: inherited(t0, t1, t2, t3, detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull(),
detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4)
: inherited(t0, t1, t2, t3, t4, detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4,
typename access_traits<T5>::parameter_type t5)
: inherited(t0, t1, t2, t3, t4, t5, detail::cnull(), detail::cnull(),
detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4,
typename access_traits<T5>::parameter_type t5,
typename access_traits<T6>::parameter_type t6)
: inherited(t0, t1, t2, t3, t4, t5, t6, detail::cnull(),
detail::cnull(), detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4,
typename access_traits<T5>::parameter_type t5,
typename access_traits<T6>::parameter_type t6,
typename access_traits<T7>::parameter_type t7)
: inherited(t0, t1, t2, t3, t4, t5, t6, t7, detail::cnull(),
detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4,
typename access_traits<T5>::parameter_type t5,
typename access_traits<T6>::parameter_type t6,
typename access_traits<T7>::parameter_type t7,
typename access_traits<T8>::parameter_type t8)
: inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, detail::cnull()) {}
tuple(typename access_traits<T0>::parameter_type t0,
typename access_traits<T1>::parameter_type t1,
typename access_traits<T2>::parameter_type t2,
typename access_traits<T3>::parameter_type t3,
typename access_traits<T4>::parameter_type t4,
typename access_traits<T5>::parameter_type t5,
typename access_traits<T6>::parameter_type t6,
typename access_traits<T7>::parameter_type t7,
typename access_traits<T8>::parameter_type t8,
typename access_traits<T9>::parameter_type t9)
: inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) {} : inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) {}
template<class U1, class U2> template<class U1, class U2>
tuple(const cons<U1, U2>& p) : inherited(p) {} tuple(const cons<U1, U2>& p) : inherited(p) {}

View File

@ -246,58 +246,6 @@ namespace tuples {
namespace detail { namespace detail {
#if defined(BOOST_MSVC) && (BOOST_MSVC == 1300)
// special workaround for vc7:
template <bool x>
struct reference_adder
{
template <class T>
struct rebind
{
typedef T& type;
};
};
template <>
struct reference_adder<true>
{
template <class T>
struct rebind
{
typedef T type;
};
};
// Return a reference to the Nth type of the given Tuple
template<int N, typename Tuple>
struct element_ref
{
private:
typedef typename element<N, Tuple>::RET elt_type;
enum { is_ref = is_reference<elt_type>::value };
public:
typedef reference_adder<is_ref>::rebind<elt_type>::type RET;
typedef RET type;
};
// Return a const reference to the Nth type of the given Tuple
template<int N, typename Tuple>
struct element_const_ref
{
private:
typedef typename element<N, Tuple>::RET elt_type;
enum { is_ref = is_reference<elt_type>::value };
public:
typedef reference_adder<is_ref>::rebind<const elt_type>::type RET;
typedef RET type;
};
#else // vc7
// Return a reference to the Nth type of the given Tuple // Return a reference to the Nth type of the given Tuple
template<int N, typename Tuple> template<int N, typename Tuple>
struct element_ref struct element_ref
@ -321,7 +269,6 @@ namespace tuples {
typedef typename add_reference<const elt_type>::type RET; typedef typename add_reference<const elt_type>::type RET;
typedef RET type; typedef RET type;
}; };
#endif // vc7
} // namespace detail } // namespace detail
@ -648,8 +595,8 @@ namespace tuples {
detail::assign_to_pointee<T2>(&t2), detail::assign_to_pointee<T2>(&t2),
detail::assign_to_pointee<T3>(&t3), detail::assign_to_pointee<T3>(&t3),
detail::assign_to_pointee<T4>(&t4), detail::assign_to_pointee<T4>(&t4),
detail::assign_to_pointee<T5>(&t5), detail::assign_to_pointee<T6>(&t5),
detail::assign_to_pointee<T6>(&t6)); detail::assign_to_pointee<T5>(&t6));
} }
// Tie variables into a tuple // Tie variables into a tuple

View File

@ -69,7 +69,7 @@ inline bool neq(const T1& lhs, const T2& rhs) {
neq(lhs.get_tail(), rhs.get_tail()); neq(lhs.get_tail(), rhs.get_tail());
} }
template<> template<>
inline bool neq<null_type,null_type>(const null_type&, const null_type&) { return false; } inline bool neq<null_type,null_type>(const null_type&, const null_type&) { return true; }
template<class T1, class T2> template<class T1, class T2>
inline bool lt(const T1& lhs, const T2& rhs) { inline bool lt(const T1& lhs, const T2& rhs) {

View File

@ -36,6 +36,8 @@
#include "boost/tuple/tuple.hpp" #include "boost/tuple/tuple.hpp"
namespace boost { namespace boost {
namespace tuples { namespace tuples {

View File

@ -395,7 +395,6 @@ equality_test()
tuple<int, char> t4(2, 'a'); tuple<int, char> t4(2, 'a');
BOOST_TEST(t1 != t3); BOOST_TEST(t1 != t3);
BOOST_TEST(t1 != t4); BOOST_TEST(t1 != t4);
BOOST_TEST(!(t1 != t2));
} }