问题
The following code fails in compilation by g++ -std=c++11 compiler.
# include<iostream>
# include<vector>
using namespace std;
# define stlf(x) x.begin(), x.end()
# define repf(it, a, b) for(auto it = a ; it != b ; ++it)
/*
// Also, following alternative fails
# define repf(it, a, b) for(auto it = a ; it != b ; ++it)
# define stlf(x) x.begin(), x.end()
*/
typedef vector<int > vi;
# define pd(x) printf("%d", x);
int main(void){
vi arr(10, -1);
repf(arr, stlf(arr))
pd(arr[i]);
return 0;
}
1. Why is this happening ?
2. What could have been implementation problem for C++ Pre-Processor implementors, that they avoided this feature ?
3. How can I then use such shortcuts ??
回答1:
Your two alternatives are identical. The order that macros are defined in is irrelevant to their expansion; it's only relevant what they are defined as at the time of expansion.
Why is this happening ?
You're invoking the macro repf
with two arguments, but it takes three arguments. That is an error, plain and simple, so preprocessing fails.
What could have been implementation problem for C++ Pre-Processor implementors, that they avoided this feature ?
I think you're making an unwarranted assumption here. The issue isn't that the preprocessor "lacks" some "feature"; it's that your expectations of how the preprocessor works is wrong.
Presumably, you expect the preprocessor to do something like this:
repf(arr, stlf(arr))
repf(arr, arr.begin(), arr.end())
for(auto it = arr.begin() ; it != arr.end() ; ++it)
...where from step 1 to step 2, stlf(arr)
gets expanded; then its expansion is put into the call to repf
, which then gets expanded at step 3.
The problem is, that is not how the preprocessor works. Given the example is broken, I can't illustrate the steps properly with this, so let's suppose we do this instead for illustration purposes:
#define FOO(X, Y) BAR(X, Y)
#define BAR(X,Y,Z) x is X y is Y z is Z
#define ACOMMAB A, B
FOO(ACOMMAB, C)
That last line expands to x is A y is B c is Z
, and it works more like this:
FOO(ACOMMAB, C)
BAR(ACOMMAB, C)
BAR(A, B, C)
x is A y is B c is Z
Note that the inner macro doesn't expand first; rather, the outer macro does. Note also that this example injects a comma; so injecting a comma is definitely something you can in fact do, which I assume to be the "feature" you refer to that was avoided.
How can I then use such shortcuts ??
Given the preprocessor doesn't work the way you think it does, you probably don't want to use it to do what you think you want to use it to do... even for speed coding. stlf
will gladly build two arguments for you for function calls, but macros are not functions. Ranged for seems to be your best bet.
回答2:
The issue is, as H Walters points out, the order in which macros do things
- read (parse) arguments from the input token stream
- expand macros in those arguments (unless they are involved with a # or ## operator)
- substitute those (expanded) arguments into the body of the macro
- rescan the body for other macros to expand.
Note that there are two places in the above where other macros may be expanded, so while the order may be wrong for what you want to do, you may be able to make it right by adding additional macro calls to get things to happen when you want. For example, if you have a macro
#define expand(...) __VA_ARGS__
which does nothing (just takes one or more arguments and expands macros in them), you can use it to get additional macro expansion in the right place:
expand( repf expand((arr, stlf(arr))) )
will expand to your desired for(auto it = arr.begin() ; it != arr.end() ; ++it)
That may seem unwieldy, but you can wrap the calls to expand in another recrusive macro:
# define stlf(x) x.begin(), x.end()
# define expand(...) __VA_ARGS__
# define repf(...) expand(repf2 expand((__VA_ARGS__)))
# define repf2(it, a, b) for(auto it = a ; it != b ; ++it)
and now repf(arr, stlf(arr))
expands the way you want it to.
回答3:
repf
is expecting 3 arguments and you are passing just 2. You cannot use another macro's expansion result (stlf
) as an argument (for another Macro). Pre-processor/compiler aren't designed this way.
I'm not against macro (they are extremely useful in many cases), but for this simple case you must not be using macro. It makes your program hard to read, maintain and debug. Avoid!
Ideally, range based for loop you should be using instead (no macro):
for(int a : arr) ...
回答4:
It should be something like this:
define repf(it, a) for(auto it = std::begin(a) ; it != std::end(a) ; ++it)
But why are you using macros for this?
来源:https://stackoverflow.com/questions/44276528/using-nested-macro-with-different-number-of-arguments-in-c