David said:
On Tue, 20 Apr 2004 03:56:40 -0700 in comp.lang.c++, "Paul Mensonides"
Sure you are. After several back-and-forth you have not posted one
single #define to illustrate a single one of your claims. I go to the
files you list:
I have posted references to well-respected libraries. I can certainly post a
simple example, but it would only be a toy, such as:
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#ifndef ADD_MAX_ARITY
#define ADD_MAX_ARITY 100
#endif
#define item(z, n, _) \
BOOST_PP_EXPR_IF(n, +) BOOST_PP_CAT(p, n) \
/**/
#define add(z, n, _) \
template<class T> inline T add( \
BOOST_PP_ENUM_PARAMS( \
BOOST_PP_INC(n), T p \
) \
) { \
return BOOST_PP_REPEAT(BOOST_PP_INC(n), item, ~); \
} \
/**/
BOOST_PP_REPEAT(ADD_MAX_ARITY, add, ~)
#undef item
#undef add
As I said, this example is nothing but a toy, but nevertheless, with a tiny
amount of lateral thought, it is illustrative. It defines 100 function
overloads that add a series of numbers, such as:
template<class T> inline T add(T p0) {
return p0;
}
template<class T> inline T add(T p0, T p1) {
return p0 + p1;
}
template<class T> inline T add(T p0, T p1, T p2) {
return p0 + p1 + p2;
}
// etc.
Assuming that the "add" function is useful--which it generally isn't--it takes
two user-defined macros and one line of code to generate the equivalent of 300+
lines of source code.
Not a #define in sight except for
#if !defined(BOOST_SPIRIT_RULE_HPP)
#define BOOST_SPIRIT_RULE_HPP
template <
BOOST_PP_ENUM_PARAMS(
BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT,
typename ScannerT
)struct scanner_list : scanner_base {};
This is preprocessor metaprogramming. It is expanding the library as needed by
a user based on BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT. In this case specifically,
if BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT is 3 for example, it generates:
template <
typename ScannerT0, typename ScannerT1, typename ScannerT2struct scanner_list : scanner_base {};
Not a #define in sight except for
#if !defined(BOOST_SPIRIT_RULE_IPP)
#define BOOST_SPIRIT_RULE_IPP
The entire rest of the file after the second line that says:
#if BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT > 1
is all preprocessor metaprogramming stuff--namely macro definitions that are
repeated, etc., by Boost.Preprocessor, which is a preprocessor metaprogramming
library. As above, this is generating code that expands the capacity of the
library.
Not present in the version of Spirit I am using.
Not present in the version of Spirit I am using.
These two are in the latest Boost CVS. However, I believe with Spirit, the
Boost CVS lags behind the separate Spirit CVS (though I'm not absolutely sure of
that). They aren't, AFAICS, in the current Spirit CVS.
I give up. It is like "Read the encyclopedia and you will see what I
mean."
I'm not going to explain the entire field of generative preprocessor
metaprogramming to you. I've already given you the basic idea: using the
preprocessor to generate, among other things, repetitious code. Because you
fail to see the obvious--like all the inclusions of Boost.Preprocessor
files--doesn't mean that it isn't there--in Spirit as well as all the other
libraries that I mentioned and more besides.
This is the exact result of bias without reason and is precisely why guidelines
such as "avoid macros" are dangerous. That generalization is invalid. It needs
to be broken down into more specific guidelines that aren't based on an abstract
feeling of paranoia and fear caused by many ill uses of the preprocessor in the
past.
Total floating abstract nonsense. Source code is what comes out of
your keyboard; and it includes whatever preprocessor macros you
write. If
you "generate" it, it wouldn't be *source*.
That is completely ridiculous. If a macro expands to some C++ code, it is
reasonable to call the process "generating source code." Obviously, by virtue
only of pedantic technicality, it isn't actually the source code itself.
Further, *of course* the above is abstract, since there are already plenty of
concrete examples that I already pointed out to you that do actual real work
instead of a toy example that I could provide here. Take a look at any file at
all in Boost--including Spirit and Fusion--that includes a
So, in trying to fathom what, if anything, you are talking about, I
run
in to the following comment from Joel. Kinda sums it all up:
Yes, and if you actually read it, you'd know what it is talking about
specifically: using a macro to generate a function for a specific type. Of
course that's a hack to work around instantiation depth problems and, as such,
is less than ideal. All other things being equal--of course this is a worse
solution.
How about this other quote from Joel in a conversation that I was having with
him and Hartmut a while back:
Joel:
Kinda sums it all up, but there's more (and these are from the Boost list so you
can find them in case you don't believe me--again):
Joel:
Here's another one...
Someone:
And another one...
Joel:
Maybe you think that you know everything that you need to to make such
generalizations, but you need to realize that there are *a lot* of good uses of
the preprocessor that have nothing to do with include guards, assertions, or
preprocessor "variables".
Regards,
Paul Mensonides