#define BOOST_PP_ITERATION_LIMITS (0, 10)
#define N() 5 #define BOOST_PP_ITERATION_LIMITS (0, N() + 5)
#define A 0 #define B 10 #define BOOST_PP_ITERATION_LIMITS(A, B) // note: no whitespace ^
#define A 0 #define B 10 #define BOOST_PP_ITERATION_LIMITS (A, B) // note: has whitespace ^
#define BOOST_PP_FILENAME_1 "file.h" // -or- #define BOOST_PP_FILENAME_1 <file.h>
??=include BOOST_PP_ITERATE()
??=
token is a trigraph for #
. I use the
trigraph to make it clear that I am including a file rather than
defining or expanding a macro, but it is not necessary. Even the digraph
version, %:
, could be used. Some compilers do not readily
accept trigraphs and digraphs, so keep that in mind. Other than that, use
whichever one you prefer.)
#define BOOST_PP_ITERATION_LIMITS (1, 10) #define BOOST_PP_FILENAME_1 "file.h" ??=include BOOST_PP_ITERATE()
#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 10, "file.h")) ??=include BOOST_PP_ITERATE()
// file.h template<> struct sample<BOOST_PP_ITERATION()> { };
template<int> struct sample; #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "file.h")) ??=include BOOST_PP_ITERATE()
template<> struct sample<1> { }; template<> struct sample<2> { }; template<> struct sample<3> { }; template<> struct sample<4> { }; template<> struct sample<5> { };
// sample.h #if !BOOST_PP_IS_ITERATING #ifndef SAMPLE_H #define SAMPLE_H #include <boost/preprocessor/iteration/iterate.hpp> template<int> struct sample; #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "sample.h")) ??=include BOOST_PP_ITERATE() #endif // SAMPLE_H #else template<> struct sample<BOOST_PP_ITERATION()> { }; #endif
// sample.h #if !BOOST_PP_IS_ITERATING #ifndef SAMPLE_H #define SAMPLE_H #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_shifted_params.hpp> template<int> struct sample; #define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 5, "sample.h", 1)) ??=include BOOST_PP_ITERATE() template<class T, class U> struct typelist_t { typedef T head; typedef U tail; }; template<int> struct typelist; struct null_t; template<> struct typelist<1> { template<class T0> struct args { typedef typelist_t<T0, null_t> type; }; }; #ifndef TYPELIST_MAX #define TYPELIST_MAX 50 #endif #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, TYPELIST_MAX, "sample.h", 2)) ??=include BOOST_PP_ITERATE() #endif // SAMPLE_H #elif BOOST_PP_ITERATION_FLAGS() == 1 template<> struct sample<BOOST_PP_ITERATION()> { }; #elif BOOST_PP_ITERATION_FLAGS() == 2 #define N BOOST_PP_ITERATION() template<> struct typelist<N> { template<BOOST_PP_ENUM_PARAMS(N, class T)> struct args { typedef typelist_t< T0, typename typelist<N - 1>::args<BOOST_PP_ENUM_SHIFTED_PARAMS(N, T)>::type > type; }; }; #undef N #endif
sample
iteration and a
typelist linearization iteration.
typelist<3>::args<int,
double, char>::type
.
// extract.h #if !BOOST_PP_IS_ITERATING #ifndef EXTRACT_H #define EXTRACT_H #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> // certain types such as "void" can't be function argument types template<class T> struct incomplete { typedef T type; }; template<class T> struct strip_incomplete { typedef T type; }; template<class T> struct strip_incomplete<incomplete<T> > { typedef T type; }; template<template<int> class output, class func_t> struct extract; #ifndef EXTRACT_MAX #define EXTRACT_MAX 50 #endif #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, EXTRACT_MAX, "extract.h")) ??=include BOOST_PP_ITERATE() #endif // EXTRACT_H #else #define N BOOST_PP_ITERATION() #define STRIP(z, n, _) \ typename strip_incomplete<T ## n>::type \ /**/ template<template<int> class output, class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> struct extract<R (BOOST_PP_ENUM_PARAMS(N, T))> { typedef typename output<N>::template args<BOOST_PP_ENUM(N, STRIP, nil)>::type type; }; #undef STRIP #undef N #endif
#define TYPELIST(args) extract<typelist, void args>::type typedef TYPELIST((int, double, incomplete<void>)) xyz;
void
can't be the type of an argument, so they have to be wrapped with incomplete<T>
.
Second, the necessary double parenthesis is annoying. If and when C++
gets C99's variadic macros, TYPELIST
can be redefined:
#define TYPELIST(...) extract<typelist, void (__VA_ARGS__)>::type typedef TYPELIST(int, double, short) xyz;
#define BOOST_PP_ITERATION_PARAMS_2 /* ... */ ^
#define BOOST_PP_FILENAME_2 /* ... */ ^
for (int i = start(1); i <= finish(1); ++i) { // A for (int j = start(2); j <= finish(2); ++j) { // B } // C }
i
. BOOST_PP_ITERATION_START()
and BOOST_PP_ITERATION_FINISH() refer to start(1)
and finish(1)
respectively. At point B, however, BOOST_PP_ITERATION()
refers to j
--the current iteration value at point B.
The same is true for BOOST_PP_ITERATION_START() which refers to start(2)
,
etc..
// file.h #if !BOOST_PP_IS_ITERATING #ifndef FILE_H #define FILE_H #include <boost/preprocessor/iteration/iterate.hpp> #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 2, "file.h")) ??=include BOOST_PP_ITERATE() #endif // FILE_H #elif BOOST_PP_ITERATION_DEPTH() == 1 // A + BOOST_PP_ITERATION() #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) ??=include BOOST_PP_ITERATE() // C #elif BOOST_PP_ITERATION_DEPTH() == 2 // B - BOOST_PP_ITERATION() #endif
+ 1 - 1 - 2 + 2 - 1 - 2
i
at point A? Because of the
preprocessor's lazy evaluation, this doesn't work....
// ... #elif BOOST_PP_ITERATION_DEPTH() == 1 #define I BOOST_PP_ITERATION() #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) ??=include BOOST_PP_ITERATE() #undef I #elif BOOST_PP_ITERATION_DEPTH() == 2 #define J BOOST_PP_ITERATION() // use I and J #undef I #endif
I
refers to BOOST_PP_ITERATION(),
not to the value of BOOST_PP_ITERATION() at the point of I
's
definition.
I
....
// ... #elif BOOST_PP_ITERATION_DEPTH() == 1 #define I BOOST_PP_FRAME_ITERATION(1) // ...
#define UNIQUE_TO_FILE "some_file.h" #if BOOST_PP_ITERATION_DEPTH() == 0 #define BOOST_PP_FILENAME_1 UNIQUE_TO_FILE #elif BOOST_PP_ITERATION_DEPTH() == 1 #define BOOST_PP_FILENAME_2 UNIQUE_TO_FILE #elif BOOST_PP_ITERATION_DEPTH() == 2 #define BOOST_PP_FILENAME_3 UNIQUE_TO_FILE // ... up to BOOST_PP_LIMIT_ITERATION_DIM #endif
# // detail/define_file_h.h # ifndef FILE_H # error FILE_H is not defined # endif # # if BOOST_PP_ITERATION_DEPTH() == 0 # define BOOST_PP_FILENAME_1 FILE_H # elif BOOST_PP_ITERATION_DEPTH() == 1 # define BOOST_PP_FILENAME_2 FILE_H # elif BOOST_PP_ITERATION_DEPTH() == 2 # define BOOST_PP_FILENAME_3 FILE_H # elif BOOST_PP_ITERATION_DEPTH() == 3 # define BOOST_PP_FILENAME_4 FILE_H # elif BOOST_PP_ITERATION_DEPTH() == 4 # define BOOST_PP_FILENAME_5 FILE_H # else # error unsupported iteration dimension # endif
// file.h #if !BOOST_PP_IS_ITERATING #ifndef FILE_H #define FILE_H "file.h" #define BOOST_PP_ITERATION_LIMITS (1, 10) #include "detail/define_file_h.h" ??=include BOOST_PP_ITERATE() #endif // FILE_H #else // iterated portion #endif
function_traits
template
to demonstrate a full-fledge use of the mechanism.
function_traits
template metafunction
requires the use of every major part of the file iteration mechanism.
function_traits
. The
situation is further complicated by variadic functions (i.e. functions with an
ellipsis). Therefore, for every arity, we need a variadic version as
well.
void make_spec(int i, bool variadic) { :open function_traits<i, variadic> for (int j = 0; j < i; ++j) { :parameter<j> } :close if (!variadic) { make_spec(i, true); } return; } void function_types(int max_arity) { for (int i = 0; i <= max_arity; ++i) { make_spec(i, false); } return; }
void make_spec(int j, const char* cv, bool variadic) { :open function_traits<j, cv, variadic> for (int k = 0; k < j; ++k) { parameter<k> } :close if (!variadic) { make_spec(j, cv, true); } return; } void gen_arities(const char* cv, int max_arity) { for (int j = 0; j <= max_arity; ++j) { make_spec(j, cv, false); } return; } void pointers_to_members(int max_arity) { static const char* cv_qualifiers[] = { "", "const", "volatile", "const volatile" }; for (int i = 0; i < 4; ++i) { gen_arities(cv_qualifiers[i], max_arity); } return; }
// function_traits.hpp #if !BOOST_PP_IS_ITERATING #ifndef FUNCTION_TRAITS_HPP #define FUNCTION_TRAITS_HPP #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/facilities/apply.hpp> #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/iteration/self.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> #include <boost/preprocessor/tuple/elem.hpp> // enable user-expansion #ifndef FUNCTION_TRAITS_MAX_ARITY #define FUNCTION_TRAITS_MAX_ARITY 15 #endif namespace detail { // avoid replication of "default" values struct function_traits_base { static const bool is_plain = false; static const bool is_pointer = false; static const bool is_reference = false; static const bool is_member = false; }; } // detail // no definition template<class> struct function_traits; // extract ellipsis state #define ELLIPSIS(n) \ BOOST_PP_APPLY( \ BOOST_PP_TUPLE_ELEM(2, n, ELLIPSIS_I) \ ) \ /**/ // iterate over function arities for function types #define BOOST_PP_ITERATION_PARAMS_1 \ (4, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp", 0)) \ /**/ ??=include BOOST_PP_ITERATE() // obtain a cv-qualifier by index #define QUALIFIER(n) \ BOOST_PP_APPLY( \ BOOST_PP_TUPLE_ELEM( \ 4, n, \ (BOOST_PP_NIL, (const), (volatile), (const volatile)) \ ) \ ) \ /**/ // iterate over cv-qualifiers for pointers-to-members #define BOOST_PP_ITERATION_PARAMS_1 \ (4, (0, 3, "function_traits.hpp", 1)) \ /**/ ??=include BOOST_PP_ITERATE() // remove temporary macros #undef QUALIFIER #undef ELLIPSIS // overriding jumper for pointers-to-functions template<class T> struct function_traits<T*> : function_traits<T> { static const bool is_plain = false; static const bool is_pointer = true; }; // overriding jumper for references-to-functions template<class T> struct function_traits<T&> : function_traits<T> { static const bool is_plain = false; static const bool is_reference = true; }; // eof #endif // FUNCTION_TRAITS_HPP // specializations for function types #elif BOOST_PP_ITERATION_DEPTH() == 1 \ && BOOST_PP_ITERATION_FLAGS() == 0 \ /**/ // define ellipsis state #if BOOST_PP_IS_SELFISH #define ELLIPSIS_I ((true), (...)) #else #define ELLIPSIS_I ((false), BOOST_PP_NIL) #endif #define N BOOST_PP_ITERATION() template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> struct function_traits<R (BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1))> : detail::function_traits_base { static const bool is_plain = true; typedef R function_type(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)); typedef function_type* pointer_type; typedef function_type& reference_type; static const bool has_ellipsis = ELLIPSIS(0); typedef R return_type; static const int parameter_count = N; template<int, class D = int> struct parameter; #if N // iterate over parameters #define BOOST_PP_ITERATION_PARAMS_2 \ (3, (0, N - 1, "function_traits.hpp")) \ /**/ ??=include BOOST_PP_ITERATE() #endif }; #undef N #undef ELLIPSIS_I // re-include this section for an ellipsis variant #if !BOOST_PP_IS_SELFISH #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" ??=include BOOST_PP_INCLUDE_SELF() #endif // iteration over cv-qualifiers #elif BOOST_PP_ITERATION_DEPTH() == 1 \ && BOOST_PP_ITERATION_FLAGS() == 1 \ /**/ #define BOOST_PP_ITERATION_PARAMS_2 \ (3, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp")) \ /**/ ??=include BOOST_PP_ITERATE() // generate specializations for pointers-to-members #elif BOOST_PP_ITERATION_DEPTH() == 2 \ && BOOST_PP_FRAME_FLAGS(1) == 1 \ // define ellipsis state #if BOOST_PP_IS_SELFISH #define ELLIPSIS_I ((true), (...)) #else #define ELLIPSIS_I ((false), BOOST_PP_NIL) #endif #define N BOOST_PP_ITERATION() #define Q QUALIFIER(BOOST_PP_FRAME_ITERATION(1)) template<class R, class O BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> struct function_traits<R (O::*)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q> : detail::function_traits_base { static const bool is_member = true; typedef R (O::* pointer_to_member_type)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q; typedef O class_type; typedef Q O qualified_class_type; static const bool has_ellipsis = ELLIPSIS(0); static const bool is_const = BOOST_PP_FRAME_ITERATION(1) == 1 || BOOST_PP_FRAME_ITERATION(1) == 3; static const bool is_volatile = BOOST_PP_FRAME_ITERATION(1) == 2 || BOOST_PP_FRAME_ITERATION(1) == 3; typedef R return_type; static const int parameter_count = N; template<int, class D = int> struct parameter; #if N // iterate over parameters #define BOOST_PP_ITERATION_PARAMS_3 \ (3, (0, N - 1, "function_traits.hpp")) \ /**/ ??=include BOOST_PP_ITERATE() #endif }; #undef Q #undef N #undef ELLIPSIS_I // re-include this section for an ellipsis variant #if !BOOST_PP_IS_SELFISH #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" ??=include BOOST_PP_INCLUDE_SELF() #endif // parameter specializations #else #define X BOOST_PP_ITERATION() template<class D> struct parameter<X, D> { typedef BOOST_PP_CAT(T, X) type; }; #undef X #endif
throw
specifications.
There is no way that we can completely handle it anyway because we cannot
partially specialize on throw
specifications. However, we
could accurately report the "actual" function type, etc., including the throw
specification (which the above implementation doesn't do, as it reconstructs
those types). If you like, you can figure out how to do that on your own
as an exercise.
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)