...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
There was a discussion about whether tuples should be in a separate namespace or directly in the 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
.
The other names, forming an interface for library writers (cons lists, metafunctions manipulating cons lists, ...) remain in the subnamespace ::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.
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:
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;
Tuples are internally represented as 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).
Note that null_type
is the internal representation of an empty tuple: tuple<>
inherits from null_type
.
Whether to use 0- or 1-based indexing was discussed more than thoroughly, and the following observations were made:
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.
A suggestion to provide 1-based 'name like' indexing with constants like _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.
The characters specified with tuple stream manipulators are stored within the space allocated by 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:
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?© Copyright Jaakko Järvi 2001.