
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of cppljevans@cox-internet.com
The test driver in http://boost-consulting.com/vault /Preprocessor Metaprogramming/ctor_template.zip only works if the ctor_template.hpp file #undef's the include guard as follows:
#undef boost_forwarder_ctor_template_included
However, this need is not mentioned in: http://www.boost.org/libs/preprocessor/doc/topics/file_iteration.html
Maybe it should be mentioned there or am I missing something?
The file "ctor_template.hpp" is not being used like a normal header. Rather, it is being used in a fashion similar to the body of code iterated by the file-iteration mechanism. IOW, the #include directive that includes it is acting like a function call (or macro, if you will). For this type of use, "ctor_template.hpp" shouldn't have an #include guard at all (at least, not a normal one), as it is *intended* to be included multiple times. Also, it is using what the pp-lib calls "named external arguments", which, for all intents and purposes are arguments to the "function call". The header should #undef those macros: // boost/forwarder/ctor_template.hpp #if BOOST_PP_IS_ITERATING // ----- point 1 ----- // // "include guard" (to save time) #ifndef BOOST_FORWARD_CTOR_TEMPLATE_INCLUDED #define BOOST_FORWARD_CTOR_TEMPLATE_INCLUDED #include <boost/preprocessor/iterate.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #endif // ----- point 2 ----- // // sanity check for the "named external arguments" #if !defined(BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE) \ || !defined(BOOST_FORWARDER_CTOR_TEMPLATE_BASE_TYPE) \ /**/ #error ...choke and die! #endif // initiate iteration... #define BOOST_PP_ITERATION_LIMITS \ (0, ( \ (BOOST_FORWARDER_CTOR_TEMPLATE_MAX_ARITY) \ ? (BOOST_FORWARDER_CTOR_TEMPLATE_MAX_ARITY) : 4) - 1) \ /**/ #define BOOST_PP_FILENAME_1 <boost/forwarder/ctor_template.hpp> #include BOOST_PP_ITERATE() // automatically #undef "named external arguments" #undef BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE #undef BOOST_FORWARDER_CTOR_TEMPLATE_BASE_TYPE #else #define n BOOST_PP_ITERATION() // This is a local macro. // Non-all-caps is okay // for local macros only! #if !n BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE(void) #else template<BOOST_PP_ENUM_PARAMS(n, typename U)> BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE ( BOOST_PP_ENUM_BINARY_PARAMS(n, U, _) ) #endif BOOST_FORWARDER_CTOR_TEMPLATE_BASE_TYPE(n) { } #undef n #endif Uses of the above (hopefully I didn't make any mistakes) look like (e.g. line 27 of "ctor_template_test.cpp"): #define BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE sub #define BOOST_FORWARDER_CTOR_TEMPLATE_BASE_TYPE(n) : Super(BOOST_PP_ENUM_PARAMS(n, _)) #include "boost/forwarder/ctor_template.hpp" // note: no #undef's here! That's all step one. Step two is to make this a proper interface, and to make the #include in the code immediately above *look* like what it is--not a normal header inclusion. 1) Rename "boost/forwarder/ctor_template.hpp" to "boost/forwarder/detail/ctor_template.hpp". 2) Pull everything from "point 1" to "point 2" out of this file and put it in a new "boost/forwarder/ctor_template.hpp". 3) Add the following line after the header inclusions: #define BOOST_FORWARDER_CTOR_TEMPLATE() \ <boost/forwarder/detail/ctor_template.hpp> \ /**/ After this, the client code looks like: #include <boost/forwarder/ctor_template.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> // ... #define BOOST_FORWARDER_CTOR_TEMPLATE_THIS_TYPE sub #define BOOST_FORWARDER_CTOR_TEMPLATE_BASE_TYPE(n) : Super(BOOST_PP_ENUM_PARAMS(n, _)) #include BOOST_FORWARDER_CTOR_TEMPLATE() Overall, the concept is that a file-inclusion can be viewed as a function call that does something--namely insert code into the translation unit. Adding #include-guards makes a header *not* like a function call. Or, I should say, it makes it like a function call that does nothing every time it is used after the first time. File-iteration works by repeatedly calling such a function. In the code above, the function that it calls is also the file that initiated the file-iteration. The function itself disambiguates how it is being called with BOOST_PP_IS_ITERATING. What the file-iteration mechanism is basically doing is defining a for-loop mechanism that calls a user-defined function: namespace boost { namespace preprocessor { bool is_iterating; template<class F> void iterate(int a, int z, F func) { is_iterating = true; for (; a <= z; ++a) { func(a); } is_iterating = false; return; } }} The "ctor_template.hpp" header (as it currently exists) is such a function, but its initial call (the one that starts the iteration) is done by the client, not the file-iteration mechanism. You have to write that file as if it is a function--not a header. But you should also provide a normal header that defines the interface to the function (i.e. BOOST_FORWARDER_CTOR_TEMPLATE()) and includes the files needed by the function. Make sense? In the grand scheme of things, running a file through the preprocessor (with the compiler already does) is the (more or less line by line) execution of a program whose output is fed to the underlying language parser. Both macros and headers are types of functions in this program (aside from directives, everything else is implicitly the output of the program). Both macro invocations and #include directives are types of function calls. Both the definition of a macro (i.e. #define) and the creation of a header are definitions of those functions. Viewing the process of preprocessing this way is an very enabling point-of-view--even with normal headers. Include guards are just used so that a function outputs what it outputs only once. File-iteration ties into this as non-recursive looping construct. (It is necessarily non-recursive because most preprocessors "helpfully" error on recursive includes of the same file at a very shallow depth.) Granted, the rules of the language in which this program is written are strange, but they are nevertheless quite usable. Regards, Paul Mensonides