Превращение временного stringstream к c_str () в отдельном операторе

Рассмотрите следующую функцию:

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));

Это функционировало бы как ожидалось?

14
задан AshleysBrain 12 March 2010 в 13:44
поделиться

3 ответа

Вы не можете привести временный поток к 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* - нет.

14
ответ дан 1 December 2019 в 13:33
поделиться

Если вам нравятся операторы 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));
0
ответ дан 1 December 2019 в 13:33
поделиться

Временный объект не может быть передан как неконстантная ссылка на функцию, поэтому он не находит правильный оператор потоковой передачи и вместо этого берет тот, у которого есть void * аргумент (это функция-член, поэтому ее временный вызов разрешен).

Что касается того, чтобы обойти ограничения с помощью кастинга, у меня есть ощущение, что это на самом деле UB, но я не могу сказать наверняка. Кто-то другой обязательно процитирует стандарт.

3
ответ дан 1 December 2019 в 13:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: