|
Boost : |
Subject: Re: [boost] [local] Simplifying the parenthesized syntax
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2011-02-11 13:19:53
On Thu, Feb 10, 2011 at 4:13 PM, John Bytheway
<jbytheway+boost_at_[hidden]> wrote:
> You shouldn't need to use Typeof if you extract the return type in the
> manner Steven Watanabe suggested:
Also I think I have figured out a way for the PARAMS/NAME macros to
support recursive calls so I am thinking not to provide the
parenthesized syntax macros at all.
The following code for C99:
int main () {
std::ostringstream output;
int BOOST_LOCAL_FUNCTION_PARAMS(int n, bool recursion, default false,
bind& output) {
int result = 0;
if (n < 2 ) result = 1;
else result = n * factorial(n - 1, true); // Recursive call.
if (!recursion) output << result << " ";
return result;
} BOOST_LOCAL_FUNCTION_NAME(factorial)
std::vector<int> v;
v.resize(3);
v[0] = 1; v[1] = 4; v[2] = 7;
std::for_each(v.begin(), v.end(), factorial);
std::cout << output.str() << std::endl;
return 0;
}
or for C++:
...
int BOOST_LOCAL_FUNCTION_PARAMS( (int n) (bool recursion)(default false)
(bind& output) ) {
...
Expands to code equivalent to:
int main () {
std::ostringstream output;
int // Result type (outside the `PARAMS` macro).
// On all C++ preprocessors (including C99 preprocessors) the macro:
//
// int BOOST_LOCAL_FUNCTION_PARAMS(
// (int n) (bool recursion)(default false) (bind& output) )
//
// Or, on C99 preprocessors only the macro:
//
// int BOOST_LOCAL_FUNCTION_PARAMS(
// int n, bool recursion, default false, bind& output)
//
// Expands to code equivalent to the following.
//
// NOTE:
// * Use line number __LINE__ (e.g., 29) to generate unique symbols.
// * Parameter name not available separately from its type.
// * Function name NOT available.
// In actual expansion, the following tokens are made available as macro
// parameters (and not as macro symbols) by the `PARAMS` macro:
#define PARAMS_arg_0 int n
#define PARAMS_arg_with_dflt_0 PARAMS_arg_0 // No default.
#define PARAMS_arg_1 bool recursion
#define PARAMS_arg_with_dflt_1 PARAMS_arg_1 = false
#define PARAMS_bind_0 &output
#define PARAMS_is_const_bind_0 0 // Not a constant bind.
// Function traits.
// NOTE: Following result type specified just before the `PARAMS` macro.
// Default parameter values need to be separated from their parameter types
// and names because they are not part of the function type so they cannot
// be used by the following expressions and their number cannot be count
// at compile-time using template metaprogramming.
ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1);
/** @todo This typeof requires registration of result, arg, etc type? */
typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29;
typedef boost::function_traits<function_type_29>::result_type
result_type_29;
typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29;
typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29;
// Handle bound parameters as done by Boost.ScopeEixt, deducing their types
// (using Boost.Typeof) and storing them by reference or by value.
typedef void (*bind_deduce_type_0_29)(int PARAMS_bind_0);
typedef BOOST_TYPEOF(boost::type_of::ensure_obj(
boost::scope_exit::aux::wrap(boost::scope_exit::aux::deref(
PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0)))))
bind_wrapped_type_0_29;
typedef bind_wrapped_type_0_29::type capture_bind_type_0_29;
// Hold bound parameter types and values.
struct binds_29 {
typedef capture_bind_type_0_29 bind_type_0_29;
boost::scope_exit::aux::member<bind_type_0_29, bind_deduce_type_0_29>
bind_value_0_29;
} params_29 = {
{ boost::scope_exit::aux::deref(PARAMS_bind_0,
static_cast<bind_deduce_type_0_29>(0)) }
};
// NOTE: The `args` variable is declared globally and not prefixed with
// __LINE__ so it can be used by both the `PARAMS` and `NAME`. The special
// template declaration type prevents this variable to be declared multiple
// times within the same scope.
boost::scope_exit::aux::declared<boost::scope_exit::aux::resolve<
sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
boost_local_auxXargs.value = ¶ms_29;
// Functor for local function.
class functor_29:
// Base used to assign local functions to `function_ref` which can
// then be passed as template parameter.
public ::boost::local::aux::function_base<function_type_29, 1> {
binds_29* binds; // Bound parameter values.
public:
explicit functor_29(): binds() {}
result_type_29 operator()(arg_type_0_29 arg_0, arg_type_1_29 arg_1) {
assert(binds);
return body(
binds->bind_value_0_29.value
// Using general names `arg_i` because parameter types and
// names are not separated by the preprocessor so the actual
// argument name (e.g., `n`) is not available here.
, arg_0, arg_1
);
}
// Overloading to support default parameters.
result_type_29 operator()(arg_type_0_29 arg_0) {
assert(binds);
return body(
binds->bind_value_0_29.value
, arg_0
);
}
private:
// LIMITATION: Body cannot be static because it has to access the
// member named after the function name for recursive calls (the
// function name is not know to this macro). However, ideally the body
// will be static so to prevent using `this` instead of `this_` by
// mistake (in most cases this will still cause a compile-time error
// because when functor has a different structure than the bound object
// `this_` -- but that is not the case if `this` is mistakenly used
// instead of `this` to do pointer operations). Programmers need to
// inspect the local function body code by eye and make sure that
// `this` is not used by the body code.
result_type_29 body(
#if PARAMS_is_const_bind_0
::boost::add_const< // Handle constant binding.
#endif
binds_29::bind_type_0_29
#if PARAMS_is_const_bind_0
>::type
#endif
PARAMS_bind_0
, PARAMS_arg_with_dflt_0
, PARAMS_arg_with_dflt_1)
// Local function body (programmed outside the macros).
{
int result = 0;
if (n < 2 ) result = 1;
else result = n * factorial(n - 1, true);
if (!recursion) output << result << " ";
return result;
}
// All `..._29` and `PARAMS_...` symbols are only available for within `PARAMS`
// macro expansion for the code above.
#undef PARAMS_arg0
#undef PARAMS_dflt0
#undef PARAMS_arg1
#undef PARAMS_dflt1
#undef PARAMS_bind0
// The macro:
//
// BOOST_LOCAL_FUNCTION_NAME(factorial)
//
// Expands to code equivalent to the following. Note:
//
// * Use function name `factorial` to generate unique symbols.
// * Function name `factorial` available.
// * None of the `..._29` symbols are available (different __LINE__).
// Public so it can be used to deduce local::function<> type to define
// functor that can be passed as template parameter.
public:
// Member with function name for recursive calls. This cannot be
// defined sooner because the function name is only available here.
::boost::local::function_ref<function_type_29, 1> factorial;
// Cannot be programmed in the constructor because it also sets the
// `factorial` member with name only known in this macro expansion.
void init(void* bind_params) {
binds = static_cast<binds_29*>(bind_params);
factorial = *this; // For recursion.
}
} object_factorial;
object_factorial.init(boost_local_auxXargs.value);
BOOST_TYPEOF(object_factorial.factorial) factorial(object_factorial);
// Rest of the program.
std::vector<int> v;
v.resize(3);
v[0] = 1; v[1] = 4; v[2] = 7;
std::for_each(v.begin(), v.end(), factorial);
std::cout << output.str() << std::endl;
return 0;
}
BTW, is there value in making functor_29's operator() and/or body
functions inline?
Thanks.
-- Lorenzo
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk