| [29] | 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>  | 
|---|