Странное поведение с острингстримом - PullRequest
4 голосов
/ 14 апреля 2011

Я пытался придумать умный способ объединить различные вещи в один строковый аргумент для функции без необходимости явно использовать ostringstream.Я думал о:

#define OSS(...) \
  dynamic_cast<std::ostringstream const&>(std::ostringstream() << __VA_ARGS__).str()

Однако, учитывая:

void f( string const &s ) {
  cout << s << endl;
}

int main() {
  char const *const s = "hello";

  f( OSS( '{' << s << '}' ) );

  ostringstream oss;
  oss << '{' << s << '}';
  cout << oss.str() << endl;
}

, он печатает при запуске:

123hello}
{hello}

, где 123 - код ASCII для },Почему использование макроса приводит к ошибкам?

К вашему сведению: в настоящее время я использую g ++ 4.2.1 на Mac OS X как часть Xcode 3.x.


Решение I 'м теперь с помощью

class string_builder {
public:
  template<typename T>
  string_builder& operator,( T const &t ) {
    oss_ << t;
    return *this;
  }

  operator std::string() const {
    return oss_.str();
  }

private:
  std::ostringstream oss_;
};

#define BUILD_STRING(...) (string_builder(), __VA_ARGS__)

using namespace std;

void f( string const &s ) {
  cout << s << endl;
}

int main() {
  char const *const s = "hello";

  f( BUILD_STRING( '{', s, '}' ) );
}

Ответы [ 2 ]

5 голосов
/ 14 апреля 2011

std::ostringstream() является временным, поэтому его можно связать только с константными ссылками.Автономный оператор << (который принимает неконстантные ссылки в качестве первого аргумента) не учитывается, а только член-член.Наилучшим соответствием для символа является преобразование символа в целое число. </p>

Эта проблема часто возникает с строковыми литералами, адрес которых затем отображается.

Чтобы решить эту проблему, нужно найти способспособ преобразования временного в ссылку.Элемент operator<< s делает это, но только один для манипулятора делает это без побочного эффекта, и только если манипулятор является noop-flush, можно использовать.Члены флеша и записи также являются кандидатами.Так, например,

#define OSS(...) \
    dynamic_cast<std::ostringstream const&>(std::ostringstream().flush() << __VA_ARGS__).str()
3 голосов
/ 14 апреля 2011

Лучшее поточно-ориентированное решение без использования громоздкого макроса.

Исходный вызов функции таков:

f( OSS( '{' << s << '}' ) );

Как насчет, если вызов только это:

 f(stringbuilder() << '{' << s << '}' ); 

, где stringbuilder реализован как:

struct stringbuilder
{
   std::ostringstream ss;
   template<typename T>
   stringbuilder & operator << (const T &data)
   {
        ss << data;
        return *this;
   }
   operator string() { return ss.str(); }
};

void f( string const &s ) {
  cout << s << endl;
}

Тест:

int main() {
  char const *const s = "hello";

  f(stringbuilder() << '{' << s << '}' );

}

Выход:

{hello}

Онлайн-демонстрация: http://ideone.com/QHFf4

...