Abstract
Although STL somewhat supports built-in arrays, the standard library provides no
support for getting iterators to built-in arrays. While getting an iterator to
the beginning of an array is trivial, getting a past-the-end iterator is much
harder, if not impossible (at least portably). However, it is possible to get a
past-the-end iterator for statically sized built-in arrays. This component
provides functions for better support of built-in arrays.
Synopsis
|
#include "boost/array_traits.hpp"
namespace boost
{
template <typename Container>
struct array_traits
{
typedef ... iterator;
typedef ... size_type;
static iterator begin();
static iterator end();
static size_type size();
};
template <typename Container>
array_traits<Container>::iterator begin(Container &c);
template <typename Container>
array_traits<Container>::iterator end(Container &c);
template <typename Container>
array_traits<Container>::size_type size(Container &c);
template <typename T, unsigned long sz>
char (&sizer(T (&)[sz]))[sz];
}
|
Description
The header boost/array_traits.hpp declares one
template class and a set of functions which can be used for better support of
statically sized built-in arrays. See the article
about built-in arrays for a rationale why and under which constraints built-in
arrays are still useful (for most applications, container classes, whether from
the standard library, some third party, or self-written, are superior than
built-in arrays but there are a few exceptions to this rule).
The template class array_traits is mainly an auxiliary
class used by the functions to get a consistent interface. It is specialized for
statically sized arrays and constant containers. The former does not explicitly
define an iterator type and the methods to access the beginning, the end, and
the size of this container is very different from the approach taken for STL
containers. It is necessary to specialize for constant containers because the
iterator type is a different one than for non-constant containers (const_iterator
instead of iterator).
The functions begin(), end(), and
size() can be used to replace the corresponding container
member functions: For STL conformant containers, these functions simply call the
corresponding container member functions. However, for statically sized built-in
arrays, they behave different. In this case, begin()
simply returns a pointer to the array (the type passed to the function begin()
is T (&)[size], not T*), end()
converts the argument to a pointer and adds the size of the array, and size()
returns the size.
Here is a sample program using these functions:
|
#include "boost/array_traits.hpp"
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> vec(boost::begin(arr), boost::end(arr));
std::ostream_iterator<int> oit(std::cout, " ");
std::cout << "size: " << boost::size(arr) << "\n";
std::copy(boost::begin(arr), boost::end(arr), oit);
std::cout << "\n";
std::cout << "size: " << boost::size(vec) << "\n";
std::copy(boost::begin(vec), boost::end(vec), oit);
std::cout << "\n";
return 0;
}
|
Note that this example uses absolutely identical code to print the array and the
vector. Using the same code is essential when writing templates. However, using end(array)
instead of either hardcoding the size of the array or using some macro is also
convenient in other contexts when a statically size array is used (using a macro
for this is as convenient as using the function end() but
it is not safe: the macro could be called on a pointer, too, yielding false
results).
Actually, this example should use a template function which gets the
container as argument. This is not used because none of the compilers used to
test this code could compile it...
Bugs
Currently, this code needs (b)leading edge compilers. Thus, only few
compilers compile this code successfully. I was able to get the code working for
egcs-2.92.23 (that is, the snapshot from 1998-11-22) and EDG-2.39 but I needed
some extra code for both compilers to make it work. Although this code should
not be harmful to standard conforming compilers, it should be remove once it is
no longer necessary. The only other compiler I tested was MSVC++ 6.0 but this
failed with no hope to make things work... (this compiler already flagged errors
when only the array version of the three functions were used; I gave up before
coming around to test whether partial specialization needed for array_traits
works).
The result of the size() function cannot be used as an
integral constant. This is the major flaw with this code. It is possible to
write a macro which is an integral constant... However, in a discussion in
comp.lang.c++.moderated a safe method for getting the size of an array as
integral constant was proposed. The basic idea is to use the sizeof
operator to a function returning a reference to an appropriately sized array of chars:
The result of the sizeof operator applied to this function
can be used as an integral constant. To do this, the function sizer()
is declared (it is not necessary to define this function since the argument to
the sizeof operator is never evaluated) is declared in boost/array_traits.hpp.
Here is an example:
|
#include "boost/array_traits.hpp"
#include <algorithm>
int main()
{
int source[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int destination[sizeof(boost::sizer(source))];
std::copy(boost::begin(source), boost::end(source), boost::begin(destination));
}
|
See Also
array-article(3)
History
The header was previously named array.hpp
Copyright © 1998 Dietmar Kühl
(dietmar.kuehl@claas-solutions.de)
Claas Solutions GmbH