Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing an initialization list to a macro

Why doesn't the commented out line in the following program compile?

#include <iostream>
#include <vector>
using namespace std;

#define F1(a) 1

int F2(vector<int>) { return 2; }

int main() {
    vector<int> v;
    v = vector<int>{1,2,3};

    cout << F1( v ) << endl;
    //The following line doesn't compile. The error is:
    //error: macro "F" passed 3 arguments, but takes just 1
    //cout << F1( vector<int>{1,2,3} ) << endl; // <- error!
    cout << F1( vector<int>({1,2,3}) ) << endl;
    cout << F1( (vector<int>{1,2,3}) ) << endl;

    cout << F2( v ) << endl;
    //The following line compiles fine
    cout << F2( vector<int>{1,2,3} ) << endl;
    cout << F2( vector<int>({1,2,3}) ) << endl;
    cout << F2( (vector<int>{1,2,3}) ) << endl;

    return 0;
}
like image 391
Baruch Avatar asked May 21 '15 11:05

Baruch


3 Answers

The preprocessor does not know about {} initialisation. It sees the comma and thinks that's the start of a new macro argument. And then the next one. Only brackets () are things that it knows about.

[C++11: 16.3/11]: The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments. [..]

like image 149
Lightness Races in Orbit Avatar answered Nov 16 '22 06:11

Lightness Races in Orbit


A macro is not a function. It interprets your input vector<int>{1,2,3} as 3 inputs, which are vector<int>{1,2 and 3}. You can change this by making it an expression (vector<int>{1,2,3}) (as you already did).

Everything in parantheses is an expression and vector<int>(...) is a (*special member-)function so the preprocessor sees it as one expression.

like image 29
Otomo Avatar answered Nov 16 '22 06:11

Otomo


Another workaround is to transform your MACRO into a variadic MACRO

#define F1(...) 1

Or in a more general case; turn:

#define M(a) a

into this:

#define M(...) __VA_ARGS__
like image 11
Jarod42 Avatar answered Nov 16 '22 07:11

Jarod42