Подтвердить что ты не робот

Передача списка инициализации в макрос

Почему не комментируется прокомментированная строка в следующей программе?

#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;
}
4b9b3361

Ответ 1

Препроцессор не знает об инициализации {}. Он видит запятую и думает, что начало нового макроса. И затем следующий. Только скобки () - это то, о чем он знает.

[C++11: 16.3/11]: Последовательность токенов предварительной обработки, ограниченных внешними наиболее совпадающими скобками, формирует список аргументов для функционально-подобного макроса. Отдельные аргументы в списке разделяются токенами предварительной обработки запятой, но маркеры предварительной обработки запятой между совпадающими внутренними скобками не разделяют аргументы. [..]

Ответ 2

Макрос не является функцией. Он интерпретирует ваш вход vector<int>{1,2,3} как 3 входа, которые являются vector<int>{1, 2 и 3}. Вы можете изменить это, сделав его выражением (vector<int>{1,2,3}) (как вы уже сделали).

Все в скобках является выражением и vector<int>(...) является функцией (* special member-), поэтому препроцессор видит это как одно из выражений.

Ответ 3

Другим обходным решением является преобразование макроса в вариационный макрос

#define F1(...) 1

Или, в более общем случае:

#define M(a) a

в

#define M(...) __VA_ARGS__