mirror of
https://github.com/boostorg/concept_check.git
synced 2026-01-25 16:32:18 +01:00
205 lines
7.8 KiB
HTML
205 lines
7.8 KiB
HTML
<HTML>
|
|
<!--
|
|
-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000
|
|
--
|
|
-- Permission to use, copy, modify, distribute and sell this software
|
|
-- and its documentation for any purpose is hereby granted without fee,
|
|
-- provided that the above copyright notice appears in all copies and
|
|
-- that both that copyright notice and this permission notice appear
|
|
-- in supporting documentation. We make no
|
|
-- representations about the suitability of this software for any
|
|
-- purpose. It is provided "as is" without express or implied warranty.
|
|
-->
|
|
<Head>
|
|
<Title>Concept Checking Implementation</Title>
|
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
|
ALINK="#ff0000">
|
|
<IMG SRC="../../boost.png"
|
|
ALT="C++ Boost" width="277" height="86">
|
|
|
|
<BR Clear>
|
|
|
|
|
|
<h2><a name="implementation">Implementation</a></h2>
|
|
|
|
Ideally we would like to catch, and indicate, the concept violation at
|
|
the point of instantiation. As mentioned in D&E[<a
|
|
href="bibliography.htm#stroustrup94:_design_evolution">2</a>], the error
|
|
can be caught by exercising all of the requirements needed by the
|
|
function template. Exactly how the requirements (the valid
|
|
expressions in particular) are exercised is a tricky issue, since we
|
|
want the code to be compiled --- <i>but not executed</i>. Our
|
|
approach is to exercise the requirements in a separate function that
|
|
is assigned to a function pointer. In this case, the compiler will
|
|
instantiate the function but will not actually invoke it. In
|
|
addition, an optimizing compiler will remove the pointer assignment as
|
|
``dead code'' (though the run-time overhead added by the assignment
|
|
would be trivial in any case). It might be conceivable for a compiler
|
|
to skip the semantic analysis and compilation of the constraints
|
|
function in the first place, which would make our function pointer
|
|
technique ineffective. However, this is unlikely because removal of
|
|
unnecessary code and functions is typically done in later stages of a
|
|
compiler. We have successfully used the function pointer technique
|
|
with GNU C++, Microsoft Visual C++, and several EDG-based compilers
|
|
(KAI C++, SGI MIPSpro). The following code shows how this technique
|
|
can be applied to the <tt>std::stable_sort()</tt> function:
|
|
|
|
<pre>
|
|
template <class RandomAccessIterator>
|
|
void stable_sort_constraints(RandomAccessIterator i)
|
|
{
|
|
typename std::iterator_traits<RandomAccessIterator>
|
|
::difference_type n;
|
|
i += n; // exercise the requirements for RandomAccessIterator
|
|
...
|
|
}
|
|
template <class RandomAccessIterator>
|
|
void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
typedef void (*fptr_type)(RandomAccessIterator);
|
|
fptr_type x = &stable_sort_constraints;
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
There is often a large set of requirements that need to be checked,
|
|
and it would be cumbersome for the library implementor to write
|
|
constraint functions like <tt>stable_sort_constraints()</tt> for every
|
|
public function. Instead, we group sets of valid expressions
|
|
together, according to the definitions of the corresponding concepts.
|
|
For each concept we define a concept checking class template where the
|
|
template parameter is for the type to be checked. The class contains
|
|
a <tt>contraints()</tt> member function which exercises all of the
|
|
valid expressions of the concept. The objects used in the constraints
|
|
function, such as <tt>n</tt> and <tt>i</tt>, are declared as data
|
|
members of the concept checking class.
|
|
|
|
<pre>
|
|
template <class Iter>
|
|
struct RandomAccessIteratorConcept
|
|
{
|
|
void constraints()
|
|
{
|
|
i += n;
|
|
...
|
|
}
|
|
typename std::iterator_traits<RandomAccessIterator>
|
|
::difference_type n;
|
|
Iter i;
|
|
...
|
|
};
|
|
</pre>
|
|
|
|
We can still use the function pointer mechanism to cause instantiation
|
|
of the constraints function, however now it will be a member function
|
|
pointer. To make it easy for the library implementor to invoke the
|
|
concept checks, we wrap the member function pointer mechanism in a
|
|
function named <tt>function_requires()</tt>. The following code
|
|
snippet shows how to use <tt>function_requires()</tt> to make sure
|
|
that the iterator is a
|
|
<a
|
|
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
|
|
RandomAccessIterator</a>.
|
|
|
|
<pre>
|
|
template <class Iter>
|
|
void stable_sort(Iter first, Iter last)
|
|
{
|
|
function_requires< RandomAccessIteratorConcept<Iter> >();
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
The definition of the <tt>function_requires()</tt> is as follows. The
|
|
<tt>Concept</tt> is the concept checking class that has been
|
|
instantiated with the modeling type. We assign the address of the
|
|
constraints member function to the function pointer <tt>x</tt>, which
|
|
causes the instantiation of the constraints function and checking of
|
|
the concept's valid expressions. We then assign <tt>x</tt> to
|
|
<tt>x</tt> to avoid unused variable compiler warnings, and wrap
|
|
everything in a do-while loop to prevent name collisions.
|
|
|
|
<pre>
|
|
template <class Concept>
|
|
void function_requires()
|
|
{
|
|
void (Concept::*x)() = BOOST_FPTR Concept::constraints;
|
|
ignore_unused_variable_warning(x);
|
|
}
|
|
</pre>
|
|
|
|
To check the type parameters of class templates, we provide the
|
|
<tt>BOOST_CLASS_REQUIRE</tt> macro which can be used inside the body of a
|
|
class definition (whereas <tt>function_requires()</tt> can only be used
|
|
inside of a function body). This macro declares a nested class
|
|
template, where the template parameter is a function pointer. We then
|
|
use the nested class type in a typedef with the function pointer type
|
|
of the constraint function as the template argument. We use the
|
|
<tt>type_var</tt> and <tt>concept</tt> names in the nested class and
|
|
typedef names to help prevent name collisions.
|
|
|
|
<pre>
|
|
#define BOOST_CLASS_REQUIRE(type_var, ns, concept) \
|
|
typedef void (ns::concept <type_var>::* func##type_var##concept)(); \
|
|
template <func##type_var##concept _Tp1> \
|
|
struct concept_checking_##type_var##concept { }; \
|
|
typedef concept_checking_##type_var##concept< \
|
|
BOOST_FPTR ns::concept<type_var>::constraints> \
|
|
concept_checking_typedef_##type_var##concept
|
|
</pre>
|
|
|
|
In addition, there are versions of <tt>BOOST_CLASS_REQUIRE</tt> that
|
|
take more arguments, to handle concepts that include interactions
|
|
between two or more types. <tt>BOOST_CLASS_REQUIRE</tt> was not used
|
|
in the implementation of the BCCL concept checks because some
|
|
compilers do not implement template parameters of function pointer
|
|
type.
|
|
|
|
<!-- We decided not to go with this version since it is easier to misuse
|
|
|
|
To check the type parameters of class templates, we provide the
|
|
<tt>class_requires</tt> class which can be used inside the body of a
|
|
class definition (whereas <tt>function_requires()</tt> can only be
|
|
used inside of a function body). <tt>class_requires</tt> declares a
|
|
nested class template, where the template parameter is a function
|
|
pointer. We then use the nested class type in a typedef with the
|
|
function pointer type of the constraint function as the template
|
|
argument.
|
|
|
|
<pre>
|
|
template <class Concept>
|
|
class class_requires
|
|
{
|
|
typedef void (Concept::* function_pointer)();
|
|
|
|
template <function_pointer Fptr>
|
|
struct dummy_struct { };
|
|
public:
|
|
typedef dummy_struct< BOOST_FPTR Concept::constraints > check;
|
|
};
|
|
</pre>
|
|
|
|
<tt>class_requires</tt> was not used in the implementation of the
|
|
Boost Concept Checking Library concept checks because several
|
|
compilers do not implement template parameters of function pointer
|
|
type.
|
|
|
|
-->
|
|
|
|
<p>
|
|
<a href="./reference.htm">Next: Reference</a><br>
|
|
<a href="prog_with_concepts.htm">Prev: Programming With Concepts</a>
|
|
|
|
<br>
|
|
<HR>
|
|
<TABLE>
|
|
<TR valign=top>
|
|
<TD nowrap>Copyright © 2000</TD><TD>
|
|
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
|
|
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
|
|
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
|
|
</TD></TR></TABLE>
|
|
|
|
</BODY>
|
|
</HTML>
|