From 8645e388d901f24c16a7347ae075222d9fe9cbb7 Mon Sep 17 00:00:00 2001
From: nobody
-There was a discussion about whether tuples should be in a separate namespace or directly in the
-The other names, forming an interface for library writers (cons lists, metafunctions manipulating cons lists, ...) remain in the subnamespace
-The subnamespace name tuples raised some discussion.
-The rationale for not using the most natural name 'tuple' is to avoid having an identical name with the tuple template.
-Namespace names are, however, not generally in plural form in boost libraries.
-First, no real trouble was reported for using the same name for a namespace and a class and we considered changing the name 'tuples' to 'tuple'.
-But we found some trouble after all.
-Both gcc and edg compilers reject using declarations where the namespace and class names are identical:
-
-
-Tuples are internally represented as
-Note that
-Whether to use 0- or 1-based indexing was discussed more than thoroughly, and the following observations were made:
-
-
-A suggestion to provide 1-based 'name like' indexing with constants like
-The characters specified with tuple stream manipulators are stored within the space allocated by © Copyright Jaakko Järvi 2001.
-
-
-
diff --git a/doc/tuple_advanced_interface.html b/doc/tuple_advanced_interface.html
deleted file mode 100644
index 4eb3ed8..0000000
--- a/doc/tuple_advanced_interface.html
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
-
-Suppose
-
-
Tuple Library : design decisions rationale
-
-About namespaces
-
-boost
namespace.
-The common principle is that domain libraries (like graph, python) should be on a separate
-subnamespace, while utility like libraries directly in the boost
namespace.
-Tuples are somewhere in between, as the tuple template is clearly a general utility, but the library introduces quite a lot of names in addition to just the tuple template.
-Tuples were originally under a subnamespace.
-As a result of the discussion, tuple definitions were moved directly under the boost
namespace.
-As a result of a continued discussion, the subnamespace was reintroduced.
-The final (I truly hope so) solution is now to have all definitions in namespace ::boost::tuples
, and the most common names in the ::boost
namespace as well.
-This is accomplished with using declarations (suggested by Dave Abrahams):
-
-With this arrangement, tuple creation with direct constructor calls, namespace boost {
- namespace tuples {
- ...
- // All library code
- ...
- }
- using tuples::tuple;
- using tuples::make_tuple;
- using tuples::tie;
- using tuples::get;
-}
-
make_tuple
or tie
functions do not need the namespace qualifier.
-Further, all functions that manipulate tuples are found with Koenig-lookup.
-The only exceptions are the get<N>
functions, which are always called with an explicitly qualified template argument, and thus Koenig-lookup does not apply.
-Therefore, get is lifted to ::boost
namespace with a using declaration.
-Hence, the interface for an application programmer is in practice under the namespace ::boost
.
-::boost::tuples
.
-Note, that the names ignore
, set_open
, set_close
and set_delimiter
are considered to be part of the application programmer's interface, but are still not under boost
namespace.
-The reason being the danger for name clashes for these common names.
-Further, the usage of these features is probably not very frequent.
-For those who are really interested in namespaces
-
-
-
-Note, however, that a corresponding using declaration in the global namespace seems to be ok:
-
-namespace boost {
- namespace tuple {
- ... tie(...);
- class tuple;
- ...
- }
- using tuple::tie; // ok
- using tuple::tuple; // error
- ...
-}
-
-
-
-
-using boost::tuple::tuple; // ok;
-
The end mark of the cons list (nil, null_type, ...)
-
-cons
lists:
-
-
-inherits from
-tuple<int, int>
-
-
-cons<int, cons<int, null_type> >
-
null_type
is the end mark of the list. Original proposition was nil
, but the name is used in MacOS, and might have caused problems, so null_type
was chosen instead.
-Other names considered were null_t and unit (the empty tuple type in SML).
-null_type
is the internal representation of an empty tuple: tuple<>
inherits from null_type
.
-Element indexing
-
-
-
-Tuple access with the syntax bind1st
, bind2nd
, pair::first
, etc.get<N>(a)
, or a.get<N>()
(where a
is a tuple and N
an index), was considered to be of the first category, hence, the index of the first element in a tuple is 0.
-
-_1st
, _2nd
, _3rd
, ... was made.
-By suitably chosen constant types, this would allow alternative syntaxes:
-
-
-
-We chose not to provide more than one indexing method for the following reasons:
-a.get<0>() == a.get(_1st) == a[_1st] == a(_1st);
-
-
-
-
-_1st
, ...).
-Let the binding and lambda libraries use these for a better purpose.a[_1st]
(or a(_1st)
) is appealing, and almost made us add the index constants after all. However, 0-based subscripting is so deep in C++, that we had a fear for confusion.Tuple comparison
-
-The comparison operator implements lexicographical order.
-Other orderings were considered, mainly dominance (a < b iff for each i a(i) < b(i)).
-Our belief is, that lexicographical ordering, though not mathematically the most natural one, is the most frequently needed ordering in everyday programming.
-
-Streaming
-
-ios_base::xalloc
, which allocates storage for long
type objects.
-static_cast
is used in casting between long
and the stream's character type.
-Streams that have character types not convertible back and forth to long thus fail to compile.
-
-This may be revisited at some point. The two possible solutions are:
-
-
-
-Back to the user's guide
-char
types as the tuple delimiters and use widen
and narrow
to convert between the real character type of the stream.
-This would always compile, but some calls to set manipulators might result in a different
- character than expected (some default character).ios_base::xalloc
.
-Any volunteers?
-
-
-
-
-
Tuple library advanced features
-
-The advanced features described in this document are all under namespace ::boost::tuples
-
-Metafunctions for tuple types
-T
is a tuple type, and N
is a constant integral expression.
-
-
-
-gives the type of the element<N, T>::type
N
th element in the tuple type T
. If T
is const, the resulting type is const qualified as well.
-Note that the constness of T
does not affect reference type
-elements.
-
-
-gives the length of the tuple type length<T>::value
T
.
-
-Tuples are internally represented as cons lists.
-For example, the tuple
-
-
-
- inherits from the type
-tuple<A, B, C, D>
-
-The tuple template provides the typedef cons<A, cons<B, cons<C, cons<D, null_type> > > >
-
inherited
to access the cons list representation. E.g.:
-tuple<A>::inherited
is the type cons<A, null_type>
.
-
-The internal representation of the empty tuple tuple<>
is null_type
.
-
-Both tuple template and the cons templates provide the typedefs head_type
and tail_type
.
-The head_type
typedef gives the type of the first element of the tuple (or the cons list).
-The
-tail_type
typedef gives the remaining cons list after removing the first element.
-The head element is stored in the member variable head
and the tail list in the member variable tail
.
-Cons lists provide the member function get_head()
for getting a reference to the head of a cons list, and get_tail()
for getting a reference to the tail.
-There are const and non-const versions of both functions.
-
-Note that in a one element tuple, tail_type
equals null_type
and the get_tail()
function returns an object of type null_type
.
-
-The empty tuple (null_type
) has no head or tail, hence the get_head
and get_tail
functions are not provided.
-
-Treating tuples as cons lists gives a convenient means to define generic functions to manipulate tuples. For example, the following pair of function templates assign 0 to each element of a tuple (obviously, the assignments must be valid operations for the element types): - -
inline void set_to_zero(const null_type&) {};
-
-template <class H, class T>
-inline void set_to_zero(cons<H, T>& x) { x.get_head() = 0; set_to_zero(x.get_tail()); }
-
-- -
-A cons list can be default constructed provided that all its elements can be default constructed. -
--A cons list can be constructed from its head and tail. The prototype of the constructor is: -
cons(typename access_traits<head_type>::parameter_type h,
- const tail_type& t)
-
-The traits template for the head parameter selects correct parameter types for different kinds of element types (for reference elements the parameter type equals the element type, for non-reference types the parameter type is a reference to const non-volatile element type).
-
-
-For a one-element cons list the tail argument (null_type
) can be omitted.
-
access_traits
-The template access_traits
defines three type functions. Let T
be a type of an element in a tuple:
-
access_traits<T>::type
maps T
to the return type of the non-const access functions (nonmeber and member get
functions, and the get_head
function).access_traits<T>::const_type
maps T
to the return type of the const access functions.access_traits<T>::parameter_type
maps T
to the parameter type of the tuple constructor.make_tuple_traits
make_tuple
functions are computed with the type function make_tuple_traits
.
-The type function call make_tuple_traits<T>::type
implements the following type mapping:
-reference_wrapper<T>
-> T&
-T
-> T
-reference_wrapper
are created with the ref
and cref
functions (see The make_tuple
function.)
-
-
-Reference wrappers were originally part of the tuple library, but they are now a general utility of boost.
-The reference_wrapper
template and the ref
and cref
functions are defined in a separate file ref.hpp
in the main boost include directory; and directly in the boost
namespace.
-
© Copyright Jaakko Järvi 2001.
- - diff --git a/doc/tuple_users_guide.html b/doc/tuple_users_guide.html deleted file mode 100644 index e794a8e..0000000 --- a/doc/tuple_users_guide.html +++ /dev/null @@ -1,529 +0,0 @@ - - --A tuple (or n-tuple) is a fixed size collection of elements. -Pairs, triples, quadruples etc. are tuples. -In a programming language, a tuple is a data object containing other objects as elements. -These element objects may be of different types. -
- -Tuples are convenient in many circumstances. -For instance, tuples make it easy to define functions that return more than one value. -
- --Some programming languages, such as ML, Python and Haskell, have built-in tuple constructs. -Unfortunately C++ does not. -To compensate for this "deficiency", the Boost Tuple Library implements a tuple construct using templates. -
- --Advanced features (describes some metafunctions etc.).
--Rationale behind some design/implementation decisions.
- - -To use the library, just include: - -
#include "boost/tuple/tuple.hpp"
-
-Comparison operators can be included with: -
#include "boost/tuple/tuple_comparison.hpp"
-
-To use tuple input and output operators, - -
#include "boost/tuple/tuple_io.hpp"
-
-Both tuple_io.hpp
and tuple_comparison.hpp
include tuple.hpp
.
-
-All definitions are in namespace ::boost::tuples
, but the most common names are lifted to namespace ::boost
with using declarations. These names are: tuple
, make_tuple
, tie
and get
. Further, ref
and cref
are defined directly under the ::boost
namespace.
-
-
A tuple type is an instantiation of the tuple
template.
-The template parameters specify the types of the tuple 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.
-The data element can be any C++ type.
-Note that void
and plain function types are valid
-C++ types, but objects of such types cannot exist.
-Hence, if a tuple type contains such types as elements, the tuple type
-can exist, but not an object of that type.
-There are natural limitations for element types that cannot
-be be copied, or that are not default constructible (see 'Constructing tuples'
- below).
-
-
-For example, the following definitions are valid tuple instantiations (A
, B
and C
are some user defined classes):
-
-
tuple<int>
-tuple<double&, const double&, const double, double*, const double*>
-tuple<A, int(*)(char, int), B(A::*)(C&), C>
-tuple<std::string, std::pair<A, B> >
-tuple<A*, tuple<const A*, const B&, C>, bool, void*>
-
-
--The tuple constructor takes the tuple elements as arguments. -For an n-element tuple, the constructor can be invoked with k arguments, where 0 <= k <= n. -For example: -
tuple<int, double>()
-tuple<int, double>(1)
-tuple<int, double>(1, 3.14)
-
-
--If no initial value for an element is provided, it is default initialized (and hence must be default initializable). -For example. - -
class X {
- X();
-public:
- X(std::string);
-};
-
-tuple<X,X,X>() // error: no default constructor for X
-tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok
-
-
-In particular, reference types do not have a default initialization:
-
-tuple<double&>() // error: reference must be
- // initialized explicitly
-
-double d = 5;
-tuple<double&>(d) // ok
-
-tuple<double&>(d+3.14) // error: cannot initialize
- // non-const reference with a temporary
-
-tuple<const double&>(d+3.14) // ok, but dangerous:
- // the element becomes a dangling reference
-
-
-Using an initial value for an element that cannot be copied, is a compile -time error: - -
class Y {
- Y(const Y&);
-public:
- Y();
-};
-
-char a[10];
-
-tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied
-tuple<char[10], Y>(); // ok
-
-
-Note particularly that the following is perfectly ok:
-Y y;
-tuple<char(&)[10], Y&>(a, y);
-
-
-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: tuple<char[10], int&>
.
-
-In sum, the tuple construction is semantically just a group of individual elementary constructions. -
- -make_tuple
function
-Tuples can also be constructed using the make_tuple
(cf. std::make_pair
) helper functions.
-This makes the construction more convenient, saving the programmer from explicitly specifying the element types:
-
tuple<int, int, double> add_multiply_divide(int a, int b) {
- return make_tuple(a+b, a*b, double(a)/double(b));
-}
-
-
--By default, the element types are deduced to the plain non-reference types. E.g: -
void foo(const A& a, B& b) {
- ...
- make_tuple(a, b);
-
-The make_tuple
invocation results in a tuple of type tuple<A, B>
.
-
-
-Sometimes the plain non-reference type is not desired, e.g. if the element type cannot be copied.
-Therefore, the programmer can control the type deduction and state that a reference to const or reference to
-non-const type should be used as the element type instead.
-This is accomplished with two helper template functions: ref
and cref
.
-Any argument can be wrapped with these functions to get the desired type.
-The mechanism does not compromise const correctness since a const object wrapped with ref
results in a tuple element with const reference type (see the fifth code line below).
-For example:
-
-
A a; B b; const A ca = a;
-make_tuple(cref(a), b); // creates tuple<const A&, B>
-make_tuple(ref(a), b); // creates tuple<A&, B>
-make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&>
-make_tuple(cref(ca)); // creates tuple<const A&>
-make_tuple(ref(ca)); // creates tuple<const A&>
-
-
-
-
-Array arguments to make_tuple
functions are deduced to reference to const types by default; there is no need to wrap them with cref
. For example:
-
make_tuple("Donald", "Daisy");
-
-
-This creates an object of type tuple<const char (&)[7], const char (&)[6]>
-(note that the type of a string literal is an array of const characters, not const char*
).
-However, to get make_tuple
to create a tuple with an element of a
-non-const array type one must use the ref
wrapper.
-
-
-Function pointers are deduced to the plain non-reference type, that is, to plain function pointer.
-A tuple can also hold a reference to a function,
-but such a tuple cannot be constructed with make_tuple
(a const qualified function type would result, which is illegal):
-
void f(int i);
- ...
-make_tuple(&f); // tuple<void (*)(int)>
- ...
-tuple<tuple<void (&)(int)> > a(f) // ok
-make_tuple(f); // not ok
-
-
--Tuple elements are accessed with the expression: - -
t.get<N>()
-
-or
-get<N>(t)
-
-where t
is a tuple object and N
is a constant integral expression specifying the index of the element to be accessed.
-Depending on whether t
is const or not, get
returns the N
th element as a reference to const or
-non-const type.
-The index of the first element is 0 and thus
-N
must be between 0 and k-1
, where k
is the number of elements in the tuple.
-Violations of these constrains are detected at compile time. Examples:
-
-double d = 2.7; A a;
-tuple<int, double&, const A&> t(1, d, a);
-const tuple<int, double&, const A&> ct = t;
- ...
-int i = get<0>(t); i = t.get<0>(); // ok
-int j = get<0>(ct); // ok
-get<0>(t) = 5; // ok
-get<0>(ct) = 5; // error, can't assign to const
- ...
-double e = get<1>(t); // ok
-get<1>(t) = 3.14; // ok
-get<2>(t) = A(); // error, can't assign to const
-A aa = get<3>(t); // error: index out of bounds
- ...
-++get<0>(t); // ok, can be used as any variable
-
-
-Note! The member get functions are not supported with MS Visual C++ compiler.
-Further, the compiler has trouble with finding the non-member get functions without an explicit namespace qualifier.
-Hence, all get
calls should be qualified as: tuples::get<N>(a_tuple)
when writing code that shoud compile with MSVC++ 6.0.
-
--A tuple can be copy constructed from another tuple, provided that the element types are element-wise copy constructible. -Analogously, a tuple can be assigned to another tuple, provided that the element types are element-wise assignable. -For example: - -
class A {};
-class B : public A {};
-struct C { C(); C(const B&); };
-struct D { operator C() const; };
-tuple<char, B*, B, D> t;
- ...
-tuple<int, A*, C, C> a(t); // ok
-a = t; // ok
-
-
-In both cases, the conversions performed are: char -> int
, B* -> A*
(derived class pointer to base class pointer), B -> C
(a user defined conversion) and D -> C
(a user defined conversion).
-
-
-Note that assignment is also defined from std::pair
types:
-
-
tuple<float, int> a = std::make_pair(1, 'a');
-
-
-
-Tuples reduce the operators ==, !=, <, >, <=
and >=
to the corresponding elementary operators.
-This means, that if any of these operators is defined between all elements of two tuples, then the same operator is defined between the tuples as well.
-
-The equality operators for two tuples a
and b
are defined as:
-
a == b
iff for each i
: ai == bi
a != b
iff exists i
: ai != bi
<, >, <=
and >=
implement a lexicographical ordering.
-
--Note that an attempt to compare two tuples of different lengths results in a compile time error.
-Also, the comparison operators are "short-circuited": elementary comparisons start from the first elements and are performed only until the result is clear. - -Examples: - -
tuple<std::string, int, A> t1(std::string("same?"), 2, A());
-tuple<std::string, long, A> t2(std::string("same?"), 2, A());
-tuple<std::string, long, A> t3(std::string("different"), 3, A());
-
-bool operator==(A, A) { std::cout << "All the same to me..."; return true; }
-
-t1 == t2; // true
-t1 == t3; // false, does not print "All the..."
-
-
-
-
-Tiers are tuples, where all elements are of non-const reference types.
-They are constructed with a call to the tie
function template (cf. make_tuple
):
-
-
int i; char c; double d;
- ...
-tie(i, c, a);
-
-
-
-The above tie
function creates a tuple of type tuple<int&, char&, double&>
.
-The same result could be achieved with the call make_tuple(ref(i), ref(c), ref(a))
.
-
-A tuple that contains non-const references as elements can be used to 'unpack' another tuple into variables. E.g.: - -
int i; char c; double d;
-tie(i, c, d) = make_tuple(1,'a', 5.5);
-std::cout << i << " " << c << " " << d;
-
-This code prints 1 a 5.5
to the standard output stream.
-
-A tuple unpacking operation like this is found for example in ML and Python.
-It is convenient when calling functions which return tuples.
-
-
-The tying mechanism works with std::pair
templates as well:
-
-
int i; char c;
-tie(i, c) = std::make_pair(1, 'a');
-
-ignore
which allows you to ignore an element assigned by a tuple.
-The idea is that a function may return a tuple, only part of which you are interested in. For example (note, that ignore
is under the tuples
subnamespace):
-
-char c;
-tie(tuples::ignore, c) = std::make_pair(1, 'a');
-
-
-
-The global operator<<
has been overloaded for std::ostream
such that tuples are
-output by recursively calling operator<<
for each element.
-
-Analogously, the global operator>>
has been overloaded to extract tuples from std::istream
by recursively calling operator>>
for each element.
-
-The default delimiter between the elements is space, and the tuple is enclosed -in parenthesis. -For Example: - -
tuple<float, int, std::string> a(1.0f, 2, std::string("Howdy folks!");
-
-cout << a;
-
-outputs the tuple as: (1.0 2 Howdy folks!)
-
--The library defines three manipulators for changing the default behavior: -
set_open(char)
defines the character that is output before the first
-element.set_close(char)
defines the character that is output after the
-last element.set_delimiter(char)
defines the delimiter character between
-elements.tuples
subnamespace.
-For example:
-cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a;
-
-outputs the same tuple a
as: [1.0,2,Howdy folks!]
-
-The same manipulators work with operator>>
and istream
as well. Suppose the cin
stream contains the following data:
-
-
(1 2 3) [4:5]
-
-The code:
-
-tuple<int, int, int> i;
-tuple<int, int> j;
-
-cin >> i;
-cin >> tuples::set_open('[') >> tuples::set_close(']') >> tules::set_delimiter(':');
-cin >> j;
-
-
-reads the data into the tuples i
and j
.
-
-
-Note that extracting tuples with std::string
or C-style string
-elements does not generally work, since the streamed tuple representation may not be unambiguously
-parseable.
-
class hand_made_tuple {
- A a; B b; C c;
-public:
- hand_made_tuple(const A& aa, const B& bb, const C& cc)
- : a(aa), b(bb), c(cc) {};
- A& getA() { return a; };
- B& getB() { return b; };
- C& getC() { return c; };
-};
-
-hand_made_tuple hmt(A(), B(), C());
-hmt.getA(); hmt.getB(); hmt.getC();
-
-
-and this code:
-
-tuple<A, B, C> t(A(), B(), C());
-t.get<0>(); t.get<1>(); t.get<2>();
-
-
-Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to optimize this kind of tuple usage. -
-
-Depending on the optimizing ability of the compiler, the tier mechanism may have a small performance penalty compared to using
-non-const reference parameters as a mechanism for returning multiple values from a function.
-For example, suppose that the following functions f1
and f2
have equivalent functionalities:
-
-
void f1(int&, double&);
-tuple<int, double> f2();
-
-
-Then, the call #1 may be slightly faster than #2 in the code below:
-
-int i; double d;
- ...
-f1(i,d); // #1
-tie(i,d) = f2(); // #2
-
-See
-[1,
-2]
- for more in-depth discussions about efficiency.
-
-
-Compiling tuples can be slow due to the excessive amount of template instantiations.
-Depending on the compiler and the tuple length, it may be more than 10 times slower to compile a tuple construct, compared to compiling an equivalent explicitly written class, such as the hand_made_tuple
class above.
-However, as a realistic program is likely to contain a lot of code in addition to tuple definitions, the difference is probably unnoticeable.
-Compile time increases between 5 to 10 percentages were measured for programs which used tuples very frequently.
-With the same test programs, memory consumption of compiling increased between 22% to 27%. See
-[1,
-2]
-for details.
-
The library code is(?) standard C++ and thus the library works with a standard conforming compiler. -Below is a list of compilers and known problems with each compiler: -
-Compiler | Problems |
gcc 2.95 | - |
edg 2.44 | - |
Borland 5.5 | Can't use function pointers or member pointers as tuple elements |
Metrowerks 6.2 | Can't use ref and cref wrappers |
MS Visual C++ | No reference elements (tie still works). Can't use ref and cref wrappers |
-[1] -Järvi J.: Tuples and multiple return values in C++, TUCS Technical Report No 249, 1999. -
- --[2] -Järvi J.: ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism, TUCS Technical Report No 267, 1999. -
- --[3] Järvi J.:Tuple Types and Multiple Return Values, C/C++ Users Journal, August 2001. -
- -Last modified 2003-09-07
- -© Copyright Jaakko Järvi 2001. - -Permission to copy, use, modify, sell and distribute this software and its documentation is granted provided this copyright notice appears in all copies. -This software and its documentation is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -
- - - - - - diff --git a/index.html b/index.html deleted file mode 100644 index 3b6f47e..0000000 --- a/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - -Automatic redirection failed, please go to doc/tuple_users_guide.html - - \ No newline at end of file diff --git a/test/Jamfile b/test/Jamfile deleted file mode 100644 index 16d0431..0000000 --- a/test/Jamfile +++ /dev/null @@ -1,20 +0,0 @@ -subproject libs/tuple/test ; - -unit-test tuple_test_bench - : tuple_test_bench.cpp -