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;
}
If a type has a default constructor, either implicitly or explicitly declared, you can use brace initialization with empty braces to invoke it. For example, the following class may be initialized by using both empty and non-empty brace initialization: C++ Copy.
Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.
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!
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With