mirror of
https://github.com/boostorg/concept_check.git
synced 2026-03-06 22:04:11 +01:00
97 lines
4.2 KiB
HTML
97 lines
4.2 KiB
HTML
|
|
<h2><a name="concept-covering">Concept Covering and Archetypes</a></h2>
|
|
|
|
We have discussed how it is important to select the minimal
|
|
requirements (concepts) for the inputs to a component, but it is
|
|
equally important to verify that the chosen concepts <i>cover</i> the
|
|
algorithm. That is, any possible user error should be caught by the
|
|
concept checks and not let slip through. Concept coverage can be
|
|
verified through the use of <i>archetype classes</i>. An archetype
|
|
class is an exact implementation of the interface associated with a
|
|
particular concept. The run-time behavior of the archetype class is
|
|
not important, the functions can be left empty. A simple test program
|
|
can then be compiled with the archetype classes as the inputs to the
|
|
component. If the program compiles then one can be sure that the
|
|
concepts cover the component.
|
|
|
|
The following code shows the archetype class for the <a
|
|
href="http://www.sgi.com/Technology/STL/trivial.html">TrivialIterator</a>
|
|
concept. Some care must be taken to ensure that the archetype is an
|
|
exact match to the concept. For example, the concept states that the
|
|
return type of <tt>operator*()</tt> must be convertible to the value
|
|
type. It does not state the more stringent requirement that the return
|
|
type be <tt>T&</tt> or <tt>const T&</tt>. That means it would be a
|
|
mistake to use <tt>T&</tt> or <tt>const T&</tt> for the return type
|
|
of the archetype class. The correct approach is to create an
|
|
artificial return type that is convertible to <tt>T</tt>, as we have
|
|
done here with <tt>input_proxy</tt>. The validity of the archetype
|
|
class test is completely dependent on it being an exact match with the
|
|
concept, which must be verified by careful (manual) inspection.
|
|
|
|
<pre>
|
|
template <class T>
|
|
struct input_proxy {
|
|
operator T() { return t; }
|
|
static T t;
|
|
};
|
|
template <class T>
|
|
class trivial_iterator_archetype
|
|
{
|
|
typedef trivial_iterator_archetype self;
|
|
public:
|
|
trivial_iterator_archetype() { }
|
|
trivial_iterator_archetype(const self&) { }
|
|
self& operator=(const self&) { return *this; }
|
|
friend bool operator==(const self&, const self&) { return true; }
|
|
friend bool operator!=(const self&, const self&) { return true; }
|
|
input_proxy<T> operator*() { return input_proxy<T>(); }
|
|
};
|
|
|
|
namespace std {
|
|
template <class T>
|
|
struct iterator_traits< trivial_iterator_archetype<T> >
|
|
{
|
|
typedef T value_type;
|
|
};
|
|
}
|
|
</pre>
|
|
|
|
Generic algorithms are often tested by being instantiated with a
|
|
number of common input types. For example, one might apply
|
|
<tt>std::stable_sort()</tt> with basic pointer types as the iterators.
|
|
Though appropriate for testing the run-time behavior of the algorithm,
|
|
this is not helpful for ensuring concept coverage because C++ types
|
|
never match particular concepts, they often provide much more than the
|
|
minimal functionality required by any one concept. That is, even
|
|
though the function template compiles with a given type, the concept
|
|
requirements may still fall short of covering the functions actual
|
|
requirements. This is why it is important to compile with archetype
|
|
classes in addition to testing with common input types.
|
|
|
|
<p>
|
|
The following is an excerpt from <a
|
|
href="./stl_concept_covering.cpp"><tt>stl_concept_covering.cpp</tt></a>
|
|
that shows how archetypes can be used to check the requirement
|
|
documentation for
|
|
<a href="http://www.sgi.com/Technology/STL/stable_sort.html">
|
|
<tt>std::stable_sort()</tt></a>. In this case, it looks like the <a
|
|
href="../utility/CopyConstructible.html">CopyConstructible</a> and <a
|
|
href="../utility/Assignable.html">Assignable</a> requirements were
|
|
forgotten in the SGI STL documentation (try removing those
|
|
archetypes). The Boost archetype classes have been designed so that
|
|
they can be layered. In this example the value type of the iterator
|
|
is composed out of three archetypes. In the archetype class reference
|
|
below, template parameters named <tt>Base</tt> indicate where the
|
|
layered archetype can be used.
|
|
|
|
<pre>
|
|
{
|
|
typedef less_than_comparable_archetype<
|
|
copy_constructible_archetype<
|
|
assignable_archetype<> > > ValueType;
|
|
random_access_iterator_archetype<ValueType> ri;
|
|
std::stable_sort(ri, ri);
|
|
}
|
|
</pre>
|
|
|