]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | <html> |
2 | <head> | |
3 | <title>motivation.html</title> | |
4 | <link rel="stylesheet" type="text/css" href="../styles.css"> | |
5 | </head> | |
6 | <body> | |
7 | <h4>Motivation</h4> | |
8 | <div> | |
9 | The C++ function and template parameter lists are special syntactic constructs, and it is impossible to directly | |
10 | manipulate or generate them using C++ constructs. | |
11 | This leads to unnecessary code repetition. | |
12 | </div> | |
13 | <div> | |
14 | Consider the implementation of the <code>is_function<></code> metafunction is Boost. | |
15 | The implementation uses an overloaded <code>is_function_tester()</code> function that is used for testing if a type is convertible | |
16 | to a pointer to a function. | |
17 | Because of the special treatment of parameter lists, it is not possible to directly match a function with an arbitrary parameter list. | |
18 | Instead, the <code>is_function_tester()</code> must be overloaded for every distinct number of parameters that is to be supported. | |
19 | For example: | |
20 | </div> | |
21 | <div class="code"><pre> | |
22 | template<class R> | |
23 | yes_type is_function_tester(R (*)()); | |
24 | ||
25 | template<class R, class A0> | |
26 | yes_type is_function_tester(R (*)(A0)); | |
27 | ||
28 | template<class R, class A0, class A1> | |
29 | yes_type is_function_tester(R (*)(A0, A1)); | |
30 | ||
31 | template<class R, class A0, class A1, class A2> | |
32 | yes_type is_function_tester(R (*)(A0, A1, A2)); | |
33 | ||
34 | // ... | |
35 | </pre></div> | |
36 | <div> | |
37 | The need for this kind of repetition occurs particularly frequently while implementing generic components or metaprogramming facilities, | |
38 | but the need also manifests itself in many far simpler situations. | |
39 | </div> | |
40 | <h4>Typical Solutions</h4> | |
41 | <div> | |
42 | Typically the repetition is done manually. | |
43 | Manual code repetition is highly unproductive, but sometimes more readable to the untrained eye. | |
44 | </div> | |
45 | <div> | |
46 | Another solution is to write an external program for generating the repeated code or use some other extra linguistic means such as a smart editor. | |
47 | Unfortunately, using external code generators has many disadvantages: | |
48 | <ul> | |
49 | <li>Writing the generator takes time. (This could be helped by using a standard generator.)</li> | |
50 | <li>It is no longer productive to manipulate C++ code directly.</li> | |
51 | <li>Invoking the generator may be difficult.</li> | |
52 | <li>Automating the invocation of the generator can be difficult in certain environments. (Automatic invocation is desirable for active libraries.)</li> | |
53 | <li>Porting and distributing the generator may be difficult or simply takes precious time.</li> | |
54 | </ul> | |
55 | </div> | |
56 | <h4>What about the preprocessor?</h4> | |
57 | <div> | |
58 | Because C++ comes with a preprocessor, one would assume that it would support these kinds of needs directly. | |
59 | Using the preprocessor in this case is highly desirable because: | |
60 | <ul> | |
61 | <li>The preprocessor is highly portable.</li> | |
62 | <li>The preprocessor is automatically invoked as part of the compilation process.</li> | |
63 | <li>Preprocessor metacode can be directly embedded into the C++ source code.</li> | |
64 | <li>Compilers generally allow viewing or outputting the preprocessed code, which can be used for debugging or to copy and paste the generated code.</li> | |
65 | </ul> | |
66 | </div> | |
67 | <div> | |
68 | Most unfortunately, the preprocessor is a very low level preprocessor that specifically does not support repetition or recursive macros. | |
69 | Library support is needed! | |
70 | </div> | |
71 | <div> | |
72 | <i>For detailed information on the capabilities and limitations of the preprocessor, please refer to the C++ standard <a href="../bibliography.html#std">[Std]</a>.</i> | |
73 | </div> | |
74 | <h4>The Motivation Example Revisited</h4> | |
75 | <div> | |
76 | Using the primitives of the preprocessor library, the <code>is_function_tester()</code>'s could be implemented like this: | |
77 | </div> | |
78 | <div class="code"><pre> | |
79 | #include <boost/preprocessor/arithmetic/inc.hpp> | |
80 | #include <boost/preprocessor/punctuation/comma_if.hpp> | |
81 | #include <boost/preprocessor/repetition.hpp> | |
82 | ||
83 | #ifndef MAX_IS_FUNCTION_TESTER_PARAMS | |
84 | #define MAX_IS_FUNCTION_TESTER_PARAMS 15 | |
85 | #endif | |
86 | ||
87 | #define IS_FUNCTION_TESTER(Z, N, _) \ | |
88 | template<class R BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, class A)> \ | |
89 | yes_type is_function_tester(R (*)(BOOST_PP_ENUM_PARAMS(N, A))); \ | |
90 | /**/ | |
91 | ||
92 | BOOST_PP_REPEAT(BOOST_PP_INC(MAX_IS_FUNCTION_TESTER_PARAMS), IS_FUNCTION_TESTER, _) | |
93 | ||
94 | #undef IS_FUNCTION_TESTER | |
95 | </pre></div> | |
96 | <div> | |
97 | In order to change the maximum number of function parameters supported, you now simply change the <code>MAX_IS_FUNCTION_TESTER_PARAMS</code> definition and recompile. | |
98 | </div> | |
99 | <hr size="1"> | |
100 | <div style="margin-left: 0px;"> | |
101 |