
On Mon, Feb 7, 2011 at 11:08 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
Hello all, Based on some prototyping that I have done so far, I think I can simplify the local function macro syntax as follows using C99 variadics: void BOOST_LOCAL_FUNCTION_PARAMS(int x, double y, // [1] bind a, bind& b, const bind c, const bind& d) { ... } BOOST_LOCLA_FUNCTION_NAME(f) f(1, 1.23); ** Note that there are NO extra parenthesis!! :-)) ** What do you think? Is this simple enough? On non-C99 preprocessors, the above will need to use sequences instead of variable length tuples: void BOOST_LOCAL_FUNCTION_PARAMS( (int x) (double y) // [2] (bind a) (bind& b) (const bind c) (const bind& d) ) { ... } BOOST_LOCLA_FUNCTION_NAME(f) f(1, 1.23); This essentially introduces the same amount of extra parenthesis as Boost.ScopeExit does -- I hope it is acceptable especially because if you have C99 you can just use [1]. I can program the _same_ macros to accept both [1] and [2] on C99, and only [2] on non-C99 preprocessors. RECURSION, ETC The above macros have the important advantage of using NO extra parenthesis on C99 but they also have the following (small?) limitations: 1) They do not allow the local function to recursively call itself (because the function name is not specified until after the body is programmed so it is not available within the body for recursive calls). 2) They always require the use of Boost.Typeof to deduce the function result type (the library already requires Boost.Typeof for variable binding anyways). 3) They do not allow to specify the local function `inline` (I still have to confirm if making a local function `inline` -- which makes all the members of the local function's local class `inline` -- actually allows the compiler to optimize something... if not, this is a mud point). In most cases these limitations might not be significant. Regardless, programmers can always use the following alternative macros to eliminate these limitations (at the cost of some extra parenthesis in the syntax). On C99 (still no extra parenthesis in the parameter list): BOOST_LOCAL_FUNCTION( // [3] (int) (inline) (factorial)(int n, bind& calculations) { int result = 1; if (n > 1) result = n * factorial(n - 1); calculations << result << std::endl; } BOOST_LOCAL_FUNCTION_END(factorial) And, on non-C99 preprocessor (extra parenthesis also in the parameter list): BOOST_LOCAL_FUNCTION( // [4] (int) (inline) (factorial)( (int n) (bind& calculations) ) { int result = 1; if (n > 1) result = n * factorial(n - 1); calculations << result << std::endl; } BOOST_LOCAL_FUNCTION_END(factorial) Again, I can program the _same_ macros to accept both [3] and [4] on C99, and only [4] on non-C99 preprocessors. DEFAULTS Default parameter values can also be specified for both set of macros (but IMO defaults look a strange on C99...). On C99 with no recursion, Boost.Typeof for result type, and no inline: void BOOST_LOCAL_FUNCTION_PARAMS(int x, default -1, const bind& a) { // [5] ... } BOOST_LOCAL_FUNCTION_NAME(f) And, on non-C99 with same limitations: void BOOST_LOCAL_FUNCTION_PARAMS( (int x)(default -1) (const bind& a) ) { // [6] ... } BOOST_LOCAL_FUNCTION_NAME(f) Or, on C99 without the recursion, etc limitations: BOOST_LOCAL_FUNCTION( // [7] (int) (inline) (factorial)(int n, default 6, bind& calculations) { ... } BOOST_LOCAL_FUNCTION_END(factorial) And on non-C99 without the recursion, etc limitations: BOOST_LOCAL_FUNCTION( // [8] (int) (inline) (factorial)( (int n)(default 6) (bind& calculations) ) { ... } BOOST_LOCAL_FUNCTION_END(factorial) IMO the parenthesis `(int n)(default 6)` make the default value look better then the comma `int n, default 6`. The following could also be possible on C99: void BOOST_LOCAL_FUNCTION_PARAMS( (int x, default -1), const bind& a) { // [9] ... } BOOST_LOCAL_FUNCTION_NAME(f) But the introduced parenthesis are not necessary and I personally find the mixed use of the parenthesis and commas confusing. What do you think? NOTE: I need to separate defaults from the parameter type-name because defaults cannot be part of a function type. I need to use `default ...` instead of `= ...` because tokens need to start with alphanumeric symbols so I can concatenate them (PP_CAT) to program something like this "if the token starts with 'default' then do ..." in the preprocessor parsing macros. I am writing a Syntax Rationale section in the library documentation that lists all the alternative syntaxes that I have been exploring, their feasibility, and the reasons behind their adoption or rejection. Thanks! -- Lorenzo