Нужен макрос для создания std :: string из std :: ostringstream и a & lt; & lt; список аргументов

Я хочу написать макрос, который принимает в качестве единственного аргумента список std :: ostream& оператор<< объединяет объекты и передает консолидированную строку как один объект std :: string в функцию. Возможность передачи объединенной строки в функцию является ключевой; В приведенном ниже примере я знаю, что сам пример может быть переписан для работы просто путем определения макроса в ERR_MSG(inputs) std::cout << "ERROR: " << inputs, но отправка вывода в std :: cout — это не цель, а просто цель теста, которую я выбрал для примера.

Я использую GCC 4.1.2 (Red Hat 4.1.2-52) и не могу обновить его. Вот очень упрощенная версия того, что я пробовал:

#include <sstream>
#include <iostream>

#define ERR_MSG(inputs) errMsg(std::ostringstream().str())           // 1
#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
<aReturnType> errMsg(const std::string& msg)                                 // use with 1 & 2
{
std::cout << "\nERROR: " << msg << "\n\n";
return <someObjectCreatedBasedOnTheInput>;
}

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)         // 3
<aReturnType> errMsg(const std::ostringstream& msg)                           // use with 3
{
std::cout << "\nERROR: " << msg.str() << "\n\n";
return <someObjectCreatedBasedOnTheInput>;
}

int main()
{
ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
}

Макрос # 1 компилируется, но, конечно, ничего не печатает, кроме «» для сообщения. Ни один макрос 2 & 3 компиляции, со следующими ошибками:

#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2
error: ‘struct std::basic_ostream<char, std::char_traits<char> >’ has no member named ‘str’

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)         // 3
no matching function for call to ‘errMsg(std::basic_ostream<char, std::char_traits<char> >&)’
note: candidates are: char* errMsg(const std::string&)
note:                 char* errMsg(const std::ostringstream&)

я не интересно, как я мог бы переписать это без макросов; Я могу сделать это довольно легко сам.

=== ОБНОВЛЕНИЕ: ===
Я забыл упомянуть, что в своем реальном случае функция, вызываемая макросом, возвращает объект, который может использовать вызывающий макрос. Это делает недействительными любые реализации макросов, которые не могут быть реализованы в одном выражении, результатом которого является возвращаемый тип функции, вызываемой макросом. Реализация макроса «ничего не делать» (для сборок релиза) просто передаст пустую строку std :: string функции независимо от того, что является «входными данными». Извините, что не упомянул об этом раньше.

0

Решение

Ваша текущая проблема заключается в том, что все operator<< функции возвращают ostream&не ostringstream&, Вы можете решить это с простой актерский состав:

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())

flush необходимо, потому что std::ostringstream() является временным. Следовательно, вы не можете вызывать функции, которые принимают ссылку на lvalue (т.е. std::ostream&). Функции, как большинство operator<< варианты. Все flush вызов это вернуть this указатель как ссылка lvalue.

3

Другие решения

Если вы готовы использовать некоторые Расширение GCC, вы могли бы объявить фактический ostringstream внутри макроса в блоке, чтобы метод .str () мог использоваться без приведения:

#define ERR_MSG(inputs) \
do { std::ostringstream _s_; _s_<<inputs;errMsg(_s_.str()); } while(false)

Демо-версия: http://ideone.com/clone/y56lc

1

использование do { } while (false) идиома, чтобы сделать несколько строк макроса.

#define ERR_MSG(inputs) \
do { \
std::ostringstream osERR_MSG; \
osERR_MSG << inputs; \
errMsg(osERR_MSG.str()); \
} while (false)int main() {
if (1) ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
else return 0;
}

Причина, по которой я сделал такое странное имя osERR_MSG чтобы избежать как можно большего количества случаев, подобных этому:

int osERR_MSG = 7;
ERR_MSG(osERR_MSG);
1

#include <sstream>
#include <iostream>

#define ERR_MSG(inputs) errMsg(std::ostringstream().flush()<<inputs)
int errMsg(std::ostream& os)
{
std::ostringstream& oss(static_cast<std::ostringstream&>(os));
const std::string& str(oss.str());
std::cout << "\nERROR: " << str << "\n\n";
return str.length();
}

int main()
{
int i = ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!");
std::cout << i << "\n";
}
1

Я бы не стал создавать std::ostringstream а есть функция, вызываемая из деструктора класса, полученного из std::ostream, Вот пример такого подхода:

#include <sstream>
#include <iostream>

void someFunction(std::string const& value)
{
std::cout << "someFunction(" << value << ")\n";
}

void method(std::string const& value)
{
std::cout << "method(" << value << ")\n";
}

class FunctionStream
: private virtual std::stringbuf
, public std::ostream
{
public:
FunctionStream()
: std::ostream(this)
, d_function(&method)
{
}
FunctionStream(void (*function)(std::string const&))
: std::ostream(this)
, d_function(function)
{
}
~FunctionStream()
{
this->d_function(this->str());
}
private:
void (*d_function)(std::string const&);
};

int main(int ac, char* av[])
{
FunctionStream() << "Hello, world: " << ac;
FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}

Пример использования не использует макрос, но его можно легко обернуть вокруг вышеупомянутого использования FunctionStream(), Обратите внимание, что в макросе вы, вероятно, хотите убедиться, что тип, видимый пользователем макроса, имеет тип std::ostream& а не временный тип, поэтому он может быть использован непосредственно с определенными пользователем операторами вывода. Для этого у вас должна быть вставка для одного из типов, непосредственно поддерживаемых std::ostream который не имеет никакого эффекта, но возвращает std::ostream&, например:

#define SomeMacro(output) FunctionStream(&someFunction) << "" << output
0

Подтверждение ответа Николя как лучшего на данный момент:

Ваша текущая проблема заключается в том, что все operator<< функции возвращают ostream&не ostringstream&, Вы можете решить это с простой актерский состав:

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str())

Конечно, это все еще имеет проблему (как и все ответы здесь), что-то вроде

ERR_MSG(x ? "x is true" : "x is false")

будет плохо себя вести странным и запутанным образом.

0
По вопросам рекламы [email protected]