ostringstream 的奇怪行为

发布于 2024-11-01 13:51:42 字数 1253 浏览 0 评论 0原文

我试图想出一种巧妙的方法,将各种内容连接到函数的单个字符串参数中,而不必显式使用 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 代码。为什么使用宏会出错?

仅供参考:我目前在 Mac OS X 上使用 g++ 4.2.1 作为 Xcode 3.x 的一部分。


我现在使用的解决方案

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, '}' ) );
}

I was trying to think of a clever way to concatenate various things into a single string argument for a function without having to use an ostringstream explicitly. I thought of:

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

However, given:

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

it prints when run:

123hello}
{hello}

where 123 is the ASCII code for }. Why does using the macro get it wrong?

FYI: I'm currently using g++ 4.2.1 on Mac OS X as part of Xcode 3.x.


Solution I'm now using

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, '}' ) );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

平安喜乐 2024-11-08 13:51:43

std::ostringstream() 是临时的,因此只能绑定到 const 引用。独立操作员<< (将非常量引用作为第一个参数)不被考虑,只有成员被考虑。其中对于 char 的最佳匹配是将 char 转换为 int。

此问题通常发生在随后显示其地址的字符串文字上。

要解决这个问题,关键是找到一种方法来转换引用中的临时值。成员operator<<可以做到这一点,但只有操纵器的成员可以做到这一点,并且没有副作用,并且只有当操纵器是noop时才能使用flush。成员flush和write也是候选人。例如

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

std::ostringstream() is temporary which thus can be bound only to const references. Standalone operator<< (which take non const references as first argument) aren't considered and only the member one are. The best match in these for a char is converting the char to int.

This problems occurs often with string literals whose address is then displayed.

To solve the problem, the trick is to find a way to transform the temporary in a reference. The member operator<<s do that, but only the one for manipulator does it without side effect and only if the manipulator is a noop -- flush could be used. The members flush and write are also candidates. So for instance

#define OSS(...) \
    dynamic_cast<std::ostringstream const&>(std::ostringstream().flush() << __VA_ARGS__).str()
蘑菇王子 2024-11-08 13:51:43

更好的线程安全解决方案,无需涉及繁琐的宏。

对函数的原始调用是这样的:

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

Test :

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

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

}

输出:

{hello}

在线演示:http://ideone.com/QHFf4

A better thread-safe solution without involving the cumbersome macro.

The original call to function is this:

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

How about if the call is just this:

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

where stringbuilder is implemented as:

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

Test:

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

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

}

Output:

{hello}

Online Demo : http://ideone.com/QHFf4

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文