ошибка компиляции при вызове функции из макроса

avatar
Arm
9 августа 2021 в 05:21
143
1
0

У нас есть МАКРОС {TT(msg)}, и внутри этого макроса мы вызываем функцию с тем же аргументом, который мы получили в макросе, т.е. 'msg'. функция, которая вызывается из макроса, ожидает строковый аргумент. Теперь предположим, что если макрос вызывается как TT("argument"), то программа компилируется и работает как положено, но если мы будем вызывать макрос как TT("argument"<<i) , то ниже приводится ошибка компиляции.

main.cpp:14:14: ошибка: недопустимые операнды типов ‘const char [4]’ и ‘int’ для двоичного ‘operator<<’

Причина проблемы: когда будет вызываться макрос TT(), он будет напрямую вызывать API func() с параметром, поскольку сообщение имеет некоторые другие значения "XYZ" << i, которые могут не обрабатываться функцией func(). так что как-то нам нужно с этим справиться.

#include <iostream>

using namespace std;
#define TT(msg) func(msg);

void func (string msg) {
    cout << msg;
    
}

int main()
{   
    int i=9;
    TT ("XYZ"<<i);
    return 0;
}
Источник

Ответы (1)

avatar
Frank
9 августа 2021 в 05:41
1

Отвечать на заданный вопрос... На мой взгляд, это плохая идея, но возможна (см. внизу ответа как):

Почему я думаю, что вам не следует использовать этот синтаксис?

При просмотре TT ("XYZ"<<i); создается впечатление, что результат выражения "XYZ"<<i передается TT(). то есть можно было бы ожидать, что следующее будет работать, но они не могут. Это просто вводит в заблуждение:

auto tmp = "XYZ" << i;  // Nope, can't do this
TT (tmp);

TT (("XYZ" << i)); // Doesn't work either.

Вместо этого я бы предложил следующее:

using namespace std;
#define TT(msg) func(msg);

std::ostream& func(string msg) {
    cout << msg;
    return cout;
}

int main()
{   
    int i=9;
    TT ("XYZ") << i;

    // or just call func() directly. TT() doesn't serve any purpose:
    func("XYZ") << i;
    return 0;
}

По сути, это тот же синтаксис, и это не приводит к путанице. Кроме того, ему не нужно создавать промежуточную строку.

Если у вас нет другого выбора, кроме как реализовать опубликованный вами синтаксис, вот как вы можете это сделать:

"Копировать-вставить" все выражение сообщения как правую часть std::ostringstream operator<<(). Обертывание всего этого в немедленно вызванную лямбду;

#include <sstream>
#define TT(msg_expr) func([&] {                            \
    std::ostringstream tmp_stream_avoid_name_collisions{}; \
    tmp_stream_avoid_name_collisions << msg_expr;          \
    return tmp_stream_avoid_name_collisions.str();         \
}());
Arm
10 августа 2021 в 06:12
0

Получение этой ошибки: main.cpp:12:62: ошибка: «класс std::basic_ostream» не имеет члена с именем «str»; ты хотел сказать "сетф"? #define TT(msg_expr) func((std::ostringstream{} << msg_expr).str());

Frank
10 августа 2021 в 11:37
0

Это потому, что версия, на которую я попал, плохо работает с тем, как operator<<() обычно перегружается. Я вернул ответ к своей первоначальной, гораздо более уродливой, но, очевидно, лучшей реализации.