| 1 | <HTML> | 
|---|
| 2 | <!-- | 
|---|
| 3 |   -- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 | 
|---|
| 4 |   -- | 
|---|
| 5 |   -- Permission to use, copy, modify, distribute and sell this software | 
|---|
| 6 |   -- and its documentation for any purpose is hereby granted without fee, | 
|---|
| 7 |   -- provided that the above copyright notice appears in all copies and | 
|---|
| 8 |   -- that both that copyright notice and this permission notice appear | 
|---|
| 9 |   -- in supporting documentation.  We make no | 
|---|
| 10 |   -- representations about the suitability of this software for any | 
|---|
| 11 |   -- purpose.  It is provided "as is" without express or implied warranty. | 
|---|
| 12 |   --> | 
|---|
| 13 | <Head> | 
|---|
| 14 | <Title>Concept Checking Implementation</Title> | 
|---|
| 15 | <BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"  | 
|---|
| 16 |         ALINK="#ff0000">  | 
|---|
| 17 | <IMG SRC="../../boost.png"  | 
|---|
| 18 |      ALT="C++ Boost" width="277" height="86">  | 
|---|
| 19 |  | 
|---|
| 20 | <BR Clear> | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 | <h2><a name="implementation">Implementation</a></h2> | 
|---|
| 24 |  | 
|---|
| 25 | Ideally we would like to catch, and indicate, the concept violation at | 
|---|
| 26 | the point of instantiation.  As mentioned in D&E[<a | 
|---|
| 27 | href="bibliography.htm#stroustrup94:_design_evolution">2</a>], the error | 
|---|
| 28 | can be caught by exercising all of the requirements needed by the | 
|---|
| 29 | function template.  Exactly how the requirements (the valid | 
|---|
| 30 | expressions in particular) are exercised is a tricky issue, since we | 
|---|
| 31 | want the code to be compiled --- <i>but not executed</i>.  Our | 
|---|
| 32 | approach is to exercise the requirements in a separate function that | 
|---|
| 33 | is assigned to a function pointer.  In this case, the compiler will | 
|---|
| 34 | instantiate the function but will not actually invoke it.  In | 
|---|
| 35 | addition, an optimizing compiler will remove the pointer assignment as | 
|---|
| 36 | ``dead code'' (though the run-time overhead added by the assignment | 
|---|
| 37 | would be trivial in any case).  It might be conceivable for a compiler | 
|---|
| 38 | to skip the semantic analysis and compilation of the constraints | 
|---|
| 39 | function in the first place, which would make our function pointer | 
|---|
| 40 | technique ineffective. However, this is unlikely because removal of | 
|---|
| 41 | unnecessary code and functions is typically done in later stages of a | 
|---|
| 42 | compiler. We have successfully used the function pointer technique | 
|---|
| 43 | with GNU C++, Microsoft Visual C++, and several EDG-based compilers | 
|---|
| 44 | (KAI C++, SGI MIPSpro).  The following code shows how this technique | 
|---|
| 45 | can be applied to the <tt>std::stable_sort()</tt> function: | 
|---|
| 46 |  | 
|---|
| 47 | <pre> | 
|---|
| 48 |   template <class RandomAccessIterator> | 
|---|
| 49 |   void stable_sort_constraints(RandomAccessIterator i) | 
|---|
| 50 |   { | 
|---|
| 51 |     typename std::iterator_traits<RandomAccessIterator> | 
|---|
| 52 |       ::difference_type n; | 
|---|
| 53 |     i += n;  // exercise the requirements for RandomAccessIterator | 
|---|
| 54 |     ... | 
|---|
| 55 |   } | 
|---|
| 56 |   template <class RandomAccessIterator> | 
|---|
| 57 |   void stable_sort(RandomAccessIterator first, RandomAccessIterator last) | 
|---|
| 58 |   { | 
|---|
| 59 |     typedef void (*fptr_type)(RandomAccessIterator); | 
|---|
| 60 |     fptr_type x = &stable_sort_constraints; | 
|---|
| 61 |     ... | 
|---|
| 62 |   } | 
|---|
| 63 | </pre> | 
|---|
| 64 |  | 
|---|
| 65 | There is often a large set of requirements that need to be checked, | 
|---|
| 66 | and it would be cumbersome for the library implementor to write | 
|---|
| 67 | constraint functions like <tt>stable_sort_constraints()</tt> for every | 
|---|
| 68 | public function.  Instead, we group sets of valid expressions | 
|---|
| 69 | together, according to the definitions of the corresponding concepts. | 
|---|
| 70 | For each concept we define a concept checking class template where the | 
|---|
| 71 | template parameter is for the type to be checked.  The class contains | 
|---|
| 72 | a <tt>contraints()</tt> member function which exercises all of the | 
|---|
| 73 | valid expressions of the concept. The objects used in the constraints | 
|---|
| 74 | function, such as <tt>n</tt> and <tt>i</tt>, are declared as data | 
|---|
| 75 | members of the concept checking class. | 
|---|
| 76 |  | 
|---|
| 77 | <pre> | 
|---|
| 78 |   template <class Iter> | 
|---|
| 79 |   struct RandomAccessIteratorConcept | 
|---|
| 80 |   { | 
|---|
| 81 |     void constraints() | 
|---|
| 82 |     { | 
|---|
| 83 |       i += n; | 
|---|
| 84 |       ... | 
|---|
| 85 |     } | 
|---|
| 86 |     typename std::iterator_traits<RandomAccessIterator> | 
|---|
| 87 |       ::difference_type n; | 
|---|
| 88 |     Iter i; | 
|---|
| 89 |     ... | 
|---|
| 90 |   }; | 
|---|
| 91 | </pre> | 
|---|
| 92 |  | 
|---|
| 93 | We can still use the function pointer mechanism to cause instantiation | 
|---|
| 94 | of the constraints function, however now it will be a member function | 
|---|
| 95 | pointer. To make it easy for the library implementor to invoke the | 
|---|
| 96 | concept checks, we wrap the member function pointer mechanism in a | 
|---|
| 97 | function named <tt>function_requires()</tt>. The following code | 
|---|
| 98 | snippet shows how to use <tt>function_requires()</tt> to make sure | 
|---|
| 99 | that the iterator is a | 
|---|
| 100 | <a | 
|---|
| 101 | href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> | 
|---|
| 102 | RandomAccessIterator</a>. | 
|---|
| 103 |  | 
|---|
| 104 | <pre> | 
|---|
| 105 |   template <class Iter> | 
|---|
| 106 |   void stable_sort(Iter first, Iter last) | 
|---|
| 107 |   { | 
|---|
| 108 |     function_requires< RandomAccessIteratorConcept<Iter> >(); | 
|---|
| 109 |     ... | 
|---|
| 110 |   } | 
|---|
| 111 | </pre> | 
|---|
| 112 |  | 
|---|
| 113 | The definition of the <tt>function_requires()</tt> is as follows. The | 
|---|
| 114 | <tt>Concept</tt> is the concept checking class that has been | 
|---|
| 115 | instantiated with the modeling type.  We assign the address of the | 
|---|
| 116 | constraints member function to the function pointer <tt>x</tt>, which | 
|---|
| 117 | causes the instantiation of the constraints function and checking of | 
|---|
| 118 | the concept's valid expressions. We then assign <tt>x</tt> to | 
|---|
| 119 | <tt>x</tt> to avoid unused variable compiler warnings, and wrap | 
|---|
| 120 | everything in a do-while loop to prevent name collisions. | 
|---|
| 121 |  | 
|---|
| 122 | <pre> | 
|---|
| 123 |   template <class Concept> | 
|---|
| 124 |   void function_requires() | 
|---|
| 125 |   { | 
|---|
| 126 |     void (Concept::*x)() = BOOST_FPTR Concept::constraints; | 
|---|
| 127 |     ignore_unused_variable_warning(x); | 
|---|
| 128 |   } | 
|---|
| 129 | </pre> | 
|---|
| 130 |  | 
|---|
| 131 | To check the type parameters of class templates, we provide the | 
|---|
| 132 | <tt>BOOST_CLASS_REQUIRE</tt> macro which can be used inside the body of a | 
|---|
| 133 | class definition (whereas <tt>function_requires()</tt> can only be used | 
|---|
| 134 | inside of a function body).  This macro declares a nested class | 
|---|
| 135 | template, where the template parameter is a function pointer. We then | 
|---|
| 136 | use the nested class type in a typedef with the function pointer type | 
|---|
| 137 | of the constraint function as the template argument. We use the | 
|---|
| 138 | <tt>type_var</tt> and <tt>concept</tt> names in the nested class and | 
|---|
| 139 | typedef names to help prevent name collisions. | 
|---|
| 140 |  | 
|---|
| 141 | <pre> | 
|---|
| 142 | #define BOOST_CLASS_REQUIRE(type_var, ns, concept) \ | 
|---|
| 143 |   typedef void (ns::concept <type_var>::* func##type_var##concept)(); \ | 
|---|
| 144 |   template <func##type_var##concept _Tp1> \ | 
|---|
| 145 |   struct concept_checking_##type_var##concept { }; \ | 
|---|
| 146 |   typedef concept_checking_##type_var##concept< \ | 
|---|
| 147 |     BOOST_FPTR ns::concept<type_var>::constraints> \ | 
|---|
| 148 |     concept_checking_typedef_##type_var##concept | 
|---|
| 149 | </pre> | 
|---|
| 150 |  | 
|---|
| 151 | In addition, there are versions of <tt>BOOST_CLASS_REQUIRE</tt> that | 
|---|
| 152 | take more arguments, to handle concepts that include interactions | 
|---|
| 153 | between two or more types. <tt>BOOST_CLASS_REQUIRE</tt> was not used | 
|---|
| 154 | in the implementation of the BCCL concept checks because some | 
|---|
| 155 | compilers do not implement template parameters of function pointer | 
|---|
| 156 | type. | 
|---|
| 157 |  | 
|---|
| 158 | <!-- We decided not to go with this version since it is easier to misuse | 
|---|
| 159 |  | 
|---|
| 160 | To check the type parameters of class templates, we provide the | 
|---|
| 161 | <tt>class_requires</tt> class which can be used inside the body of a | 
|---|
| 162 | class definition (whereas <tt>function_requires()</tt> can only be | 
|---|
| 163 | used inside of a function body).  <tt>class_requires</tt> declares a | 
|---|
| 164 | nested class template, where the template parameter is a function | 
|---|
| 165 | pointer. We then use the nested class type in a typedef with the | 
|---|
| 166 | function pointer type of the constraint function as the template | 
|---|
| 167 | argument. | 
|---|
| 168 |  | 
|---|
| 169 | <pre> | 
|---|
| 170 |   template <class Concept> | 
|---|
| 171 |   class class_requires | 
|---|
| 172 |   { | 
|---|
| 173 |     typedef void (Concept::* function_pointer)(); | 
|---|
| 174 |  | 
|---|
| 175 |     template <function_pointer Fptr> | 
|---|
| 176 |     struct dummy_struct { }; | 
|---|
| 177 |   public: | 
|---|
| 178 |     typedef dummy_struct< BOOST_FPTR Concept::constraints > check; | 
|---|
| 179 |   }; | 
|---|
| 180 | </pre> | 
|---|
| 181 |  | 
|---|
| 182 | <tt>class_requires</tt> was not used in the implementation of the | 
|---|
| 183 | Boost Concept Checking Library concept checks because several | 
|---|
| 184 | compilers do not implement template parameters of function pointer | 
|---|
| 185 | type. | 
|---|
| 186 |  | 
|---|
| 187 | --> | 
|---|
| 188 |  | 
|---|
| 189 | <p> | 
|---|
| 190 | <a href="./reference.htm">Next: Reference</a><br> | 
|---|
| 191 | <a href="prog_with_concepts.htm">Prev: Programming With Concepts</a> | 
|---|
| 192 |  | 
|---|
| 193 | <br> | 
|---|
| 194 | <HR> | 
|---|
| 195 | <TABLE> | 
|---|
| 196 | <TR valign=top> | 
|---|
| 197 | <TD nowrap>Copyright © 2000</TD><TD> | 
|---|
| 198 | <A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A | 
|---|
| 199 | HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>) | 
|---|
| 200 | Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>) | 
|---|
| 201 | </TD></TR></TABLE> | 
|---|
| 202 |  | 
|---|
| 203 | </BODY> | 
|---|
| 204 | </HTML>  | 
|---|