Рассмотрите следующую функцию:
void f(const char* str);
Предположим, что я хочу генерировать строку с помощью stringstream и передать ее этой функции. Если я хочу сделать это в одном операторе, я мог бы попробовать:
f((std::ostringstream() << "Value: " << 5).str().c_str()); // error
Это дает ошибку: 'ул. ()' не является членом 'basic_ostream'. Хорошо, таким образом, оператор <<возвращает ostream вместо ostringstream - как насчет того, чтобы бросить его назад к ostringstream?
1) Это брошено безопасное?
f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output
Теперь с этим, это собирается на оператор <<("Значение":) вызов, это на самом деле называет оператор ostream <<(пусто*) и печатает шестнадцатеричный адрес. Это неправильно, я хочу текст.
2) Почему делает оператор <<на временном станд.:: ostringstream () называют ostream оператор? Конечно, временный файл имеет тип 'ostringstream' не 'ostream'?
Я могу бросить временный файл для принуждения корректного вызова оператора также!
f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());
Это, кажется, работает и передачи "Значение: 5 дюймов к f ().
3) Я полагаюсь на неопределенное поведение теперь? Броски выглядят необычными.
Я знаю, что лучшая альтернатива - что-то вроде этого:
std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());
... но я интересуюсь поведением выполнения его в одной строке. Предположим, что кто-то хотел сделать (сомнительный) макрос:
#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())
// ...
f(make_temporary_cstr("Value: " << 5));
Это функционировало бы как ожидалось?
Вы не можете привести временный поток к std::ostringstream&
. Это неправильно (компилятор должен сказать вам, что это неправильно). Однако это можно сделать следующим образом:
f(static_cast<std::ostringstream&>(
std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());
Это, конечно, некрасиво. Но он показывает, как это может работать. seekp
- это функция-член, возвращающая std::ostream&
. Возможно, лучше было бы написать это вообще
template<typename T>
struct lval { T t; T &getlval() { return t; } };
f(static_cast<std::ostringstream&>(
lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());
Причина того, что без ничего она принимает void*
, в том, что operator<<
является функцией-членом. А operator<<
, который принимает char const*
- нет.
Если вам нравятся операторы one_ Line, вы можете написать:
// void f(const char* str);
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());
Однако вам следует предпочесть более простой код в виде:
template <typename V>
string NumberValue(V val)
{
ostringstream ss;
ss << "Value: " << val;
return ss.str();
}
f(NumberValue(5));
Временный объект не может быть передан как неконстантная ссылка на функцию, поэтому он не находит правильный оператор потоковой передачи и вместо этого берет тот, у которого есть void * аргумент (это функция-член, поэтому ее временный вызов разрешен).
Что касается того, чтобы обойти ограничения с помощью кастинга, у меня есть ощущение, что это на самом деле UB, но я не могу сказать наверняка. Кто-то другой обязательно процитирует стандарт.