Q Yao
Q Yao

Reputation: 41

C4003: Not enough actual parameters for macro in C++

Take a look at this

#define getFourth( _1,_2,_3, _4,... )  _4   //select the 4th parameter 
#define some_type(x) type, x  

getFourth
(   some_type(1),
    some_type(2),
    some_type(3)
)

I thought it expands to getFourth(type, 1, type, 2, type, 3) so we shall have 2 selected (since 2 is the 4th parameter). Instead, I got a warning "C4003 not enough actual parameters for macro 'getFourth". It appears that getFourth is treat some_type(1) as the first element, some_type(2) as the 2nd element, some_type(3) as the 3rd. Since it was expecting at least 4 parameters so we have the warning. Can someone please suggest how to fix it?

Upvotes: 2

Views: 1068

Answers (1)

H Walters
H Walters

Reputation: 2654

I thought it expands to getFourth(type, 1, type, 2, type, 3) so we shall have 2 selected (since 2 is the 4th parameter)

That's not how macros work. Macro expansion happens from the outside in. Furthermore, there are two opportunities for expansion: (1) during argument substitution, (2) with the resulting replacement list after that happens. Argument substitution expansion only occurs if the parameter in the macro corresponds to one in the replacement list (and that parameter isn't stringified with the # operator or participating in a paste (##)).

For example, if we had:

#define foo(b,c) b c
getFourth(some_type(1),some_type(2),some_type(3),foo(some_type,(4)),x)

Then getFourth now has 5 parameters, so it can be called. The first step in expansion would be argument substitution; getFourth's replacement list is _4, which only mentions one parameter. The corresponding argument is foo(some_type,(4)). Because _4 isn't being pasted or stringified, the processor can evaluate foo(some_type,(4)). That results in some_type (4), which further expands to type, 4. So now, type, 4 replaces _4. And we're done with argument substitution.

We're left with type, 4. There's one more rescan here, but nothing happens during this step. But note that some_type(1), some_type(2), and some_type(3) not only didn't get evaluated before getFourth, but they didn't get evaluated at all, because nothing in the replacement list mentions them.

Can someone please suggest how to fix it?

So long as the things you want to expand are arguments 1 through 3 of getFourth, they won't even evaluate. But you can make this just a parenthesized list, and then apply the macro, using a trick similar to what I did above:

#define CALL(a,b) a b
CALL(getFourth,(some_type(1),some_type(2),some_type(3))).

Now, getFourth and (some_type(1),some_type(2),some_type(3)) are just arguments to CALL, which mentions both parameters. So during argument substitution, getFourth itself "evaluates" (since this isn't enough to call the object-like macro, it's just left as is), and gets put into a. (some_type(1),some_type(2),some_type(3)) evaluates and gets put into b. That evaluation becomes (type, 1,type, 2,type, 3). So you wind up with getFourth (type, 1,type, 2,type, 3). Now rescan occurs, during which getFourth is called with the arguments you expect.

Upvotes: 2

Related Questions