Reputation: 1541
I just discovered that you cannot always use brace initialization when passing arguments to macros. I found this when an ASSERT() macro failed to compile. However, the following example illustrates the problem:
#include <iostream>
#include <string>
using namespace std;
#define PRINT_SIZE( f ) cout << "Size=" << (f).size() << endl;
int main()
{
PRINT_SIZE( string("ABC") ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABC"} ); // OK, prints: "Size=3"
PRINT_SIZE( string("ABCDEF",3) ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABCDEF",3} ); // Error: macro 'PRINT_SIZE' passed 2 arguments, but takes just 1
return 0;
}
Is there a reason why macros cannot be made to work with brace initialization?
Edit:
I have since discovered that you can also use a variadic macro, and that solves the problem perfectly:
#include <iostream>
#include <string>
using namespace std;
#define PRINT_SIZE( ... ) cout << "Size=" << (__VA_ARGS__).size() << endl;
int main()
{
PRINT_SIZE( string("ABC") ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABC"} ); // OK, prints: "Size=3"
PRINT_SIZE( string("ABCDEF",3) ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABCDEF",3} ); // OK, prints: "Size=3"
return 0;
}
Upvotes: 12
Views: 3807
Reputation: 363
What about this ?
#define SOME_BRACE \
{ \
6, 8, 1, 3, 7, \
1, 4, 2, 0, 9 \
}
#define BRACE_SIZE(brace) (sizeof((int[]) SOME_BRACE) / sizeof(int))
int main(int argc, char *argv[])
{
int array[BRACE_SIZE(SOME_BRACE)] = SOME_BRACE, i, s;
for (i = 0, s = 0; i < BRACE_SIZE(SOME_BRACE); i++) {
s = s + array[i];
}
/* 41 is expected */
return s;
}
Upvotes: 0
Reputation: 44063
The list is split into several macro parameters. When you write
PRINT_SIZE( string{"ABCDEF",3} );
This attempts to expand the macro PRINT_SIZE
with two parameters, one string{"ABCDEF"
and one 3}
, which fails. This can be worked around in many cases (including yours) by adding another pair of parentheses:
PRINT_SIZE( (string{"ABCDEF",3}) );
These parentheses prevent the splitting of the argument, so that PRINT_SIZE
is expanded with a single argument (string{"ABCDEF",3})
(note that the parentheses are part of the argument).
Upvotes: 18
Reputation: 40665
Yes, there is a reason: The preprocessor is not aware of braces. It only respects string literals and parentheses, to other C/C++ language structures it is ignorant. As such, the call
PRINT_SIZE( string{"ABCDEF",3} );
is parsed as a macro invocation with two parameters string{"ABCDEF"
and 3}
. Since the macro PRINT_SIZE()
expects only one parameter, the preprocessor bails out. Note that the C++ compiler has not even been invoked at this point!
Upvotes: 8