This may be veering off the path of the thread, but....
@dhayden,
Look carefully at your examples. The macro of the OP's example can't generate the second prototype "spell_fire_blast", as there is no way to specify a difference of the last parameter.
I don't have a clue from where the notion of the "spell_fire_blast" prototype uniqueness came, and perhaps I missed that in the thread somewhere above.
As such, cut and paste of the tail, from the parenthesis to the semicolon, is really all that's required to replicate what the macro does.
I submit that doesn't do much work. The actual work is at the function bodies, where this "generic" interface function is specialized to some (unknown pattern) of calls to some other API.
These are, apparently, adapter functions.
The underlying objectives and design concepts are not shown in this discussion. What we have is just talk about a macro, which we all know has been the origin of significant bugs and obfuscation, at least as often as it has been of help. I remember, I used the notion liberally before the late 80's as a C programmer, and we considered some clever macro usage as a kind of magic.
Here, all it does is save a bit of typing while obfuscating what the incoming parameters are that mate to whatever the interior calls require.
If it were possible, relative to my exchange with @jonnin, to know the entire pattern set for these "thunks" or "adapters" which apparently unify the calling signature for a disparate collection of functions, we might then realize there are, say, 25 functions with only 3 different patterns. We could then create 3 adapters (probably templates) that could be used as callable objects (pick the favorite among std::bind, std::function, even pointer to member function if that works) in those 3 styles and eliminate any need for the macro.
If we realize there are 25 different adapters, there's no choice but to write out the tedium in these function bodies, where the macro saves very little typing time compared to the clarity of seeing the incoming parameters, and that can be pasted from a previous example, just changing the name of the function as the macro itself does.
If, as @jonnin and I exchanged, it does turn out there is only 1 adaptation (that is, the OP's post showing one example body is all there is), there was never a reason for the macro in the first place, as all of those functions could be arranged for calling by some simple callable object, due to that uniformity.
So, we have a small matrix. There is a list of names, as we supply to the macro. They're the names of the function signatures he macro generates. These might be shown as the rows of a matrix.
Then, we have the adaptive signatures, that is the signature of the function being called as in the body of the OP's example. There could be 1 or more such columns.
That structure then shows how we consider the design. In this discussion we're looking at a simple, singular application. The macro does appear to be specific to some application's requirements. The overall concept is far more generic, though, and therefore moves the discussion toward the generic notions.
When we look at that matrix I propose, should it resolve to a 1 column matrix, then the macro has no purpose because no adaptations mutate. One could write one adapter to be reused for all calling situations (since there is only 1), used in any convenient "list" of callable objects.
Where there are as many columns as there are rows, it implies there's no leverage, and all translation is tedium - everything on the matrix is specialized, and the matrix is probably diagonal (or easily arranged to be diagonal).
If it is possible that the signature of the OP's macro mutates, then there would either be more parameters to the macro, or there would have to be multiple macros, which correspond to multiple pages of the matrix I proposed.
If the objective is to save typing, I submit this discussion is too focused on the macro itself, while the design requires a larger and deeper view into what is actually required here, from soup to nuts, so as to propose something that provides more leverage (even less typing) and may be far more generic (as this notion comes up in lots of examples).
Edit:
I just realized you're making a point about that situation that may arise when the signatures are not the same due to an error in repeated typing, but that's why cut/paste is about as effective as the macro itself.
I submit that trades one problem for another, though, in that what one reads here:
1 2 3 4
|
SPELL(spell_acid_blast)
{
return single_target_spell(level, ch, victim, type, DAMDICE(level, 20, 60, 11), SPELL_ACID_BLAST, SAVING_REFLEX, 0, cb_acid_scarring);
}
|
now no longer shows the incoming parameters due to obfuscation.
My thinking is that this pattern shows a hint that something deeper will yield far better advantages than the macro can.