C++ 格式宏/??内联 ostringstream

2021-12-28 00:00:00 format printing macros c++ ostringstream

我正在尝试编写一个允许我执行以下操作的宏:FORMAT(a << "b" << c << d),以及结果将是一个字符串――与创建 ostringstream、插入 a...d 并返回 .str() 相同.类似的东西:

I'm trying to write a macro that would allow me to do something like: FORMAT(a << "b" << c << d), and the result would be a string -- the same as creating an ostringstream, inserting a...d, and returning .str(). Something like:

string f(){
   ostringstream o;
   o << a << "b" << c << d;
   return o.str()
}

本质上,FORMAT(a << "b" << c << d) == f().

首先,我尝试过:

1: #define FORMAT(items)                                                   
   ((std::ostringstream&)(std::ostringstream() << items)).str()

如果第一项是 C 字符串(const char *),它将以十六进制打印字符串的地址,接下来的项将正常打印.如果第一项是 std::string,它将无法编译(没有匹配的运算符 <<).

If the very first item is a C string (const char *), it will print the address of the string in hex, and the next items will print fine. If the very first item is an std::string, it will fail to compile (no matching operator <<).

这个:

2: #define FORMAT(items)                                                   
   ((std::ostringstream&)(std::ostringstream() << 0 << '' << items)).str()

给出了看似正确的输出,但 0 当然存在于字符串中.

gives what seems like the right output, but the 0 and  are present in the string of course.

以下似乎有效,但编译时出现警告(取临时地址):

The following seems to work, but compiles with warnings (taking address of temporary):

3: #define FORMAT(items)                                                   
   ((std::ostringstream&)(*((std::ostream*)(&std::ostringstream())) << items)).str()

有谁知道为什么 1 会打印 c 字符串的地址并且无法使用 std::string 进行编译?1 和 3 本质上不是一样的吗?

Does anyone know why 1 prints the address of the c-string and fails to compile with the std::string? Aren't 1 and 3 essentially the same?

我怀疑 C++0x 可变参数模板将使 format(a, "b", c, d) 成为可能.但是现在有办法解决这个问题吗?

I suspect that C++0x variadic templates will make format(a, "b", c, d) possible. But is there a way to solve this now?

推荐答案

你们已经基本搞定了.但要遵循它有点挑战性.所以让我尝试总结一下你所说的......

You've all pretty much nailed this already. But it's a little challenging to follow. So let me take a stab at summarizing what you've said...

这里的困难在于:

  • 我们正在使用一个临时的 ostringstream 对象,所以取地址是禁忌的.

  • We are playing with a temporary ostringstream object, so taking addresses is contra-indicated.

因为它是临时的,我们不能通过强制转换简单地转换为 ostream 对象.

Because it's a temporary, we cannot trivially convert to an ostream object through casting.

构造函数[显然]和str()都是ostringstream类的方法.(是的,我们需要使用 .str().直接使用 ostringstream 对象会导致调用 ios::operator void*(),返回类似指针的好/坏值而不是字符串对象.)

Both the constructor [obviously] and str() are class ostringstream methods. (Yes, we need to use .str(). Using the ostringstream object directly would wind up invoking ios::operator void*(), returning a pointer-like good/bad value and not a string object.)

operator<<(...) 作为继承的 ostream 方法和全局函数存在.在所有情况下,它都会返回一个 ostream& 引用.

operator<<(...) exists as both inherited ostream methods and global functions. In all cases it returns an ostream& reference.

这里ostringstream()<<"foo"的选择是继承的方法ostream::operator<<(void*)和全局函数operator<<(ostream&,const char*).继承的 ostream::operator<<(void* ) 胜出,因为我们无法转换为 ostream 对象引用来调用全局函数.[感谢coppro!]

The choices here for ostringstream()<<"foo" are the inherited method ostream::operator<<(void* ) and the global function operator<<(ostream&,const char* ). The inherited ostream::operator<<(void* ) wins out because we can't convert to an ostream object reference to invoke the global function. [Kudos to coppro!]

因此,要实现这一目标,我们需要:

So, to pull this off, we need to:

  • 分配一个临时的ostringstream.
  • 将其转换为 ostream.
  • 附加数据.
  • 将其转换回 ostringstream.
  • 并调用str().

分配: ostringstream().

转换:有多种选择.其他人建议:

Converting: There are several choices. Others have suggested:

  • ostringstream() <<std::string()//感谢 *David Norman*
  • ostringstream() <<std::dec//感谢 *cadabra*

或者我们可以使用:

  • ostringstream() .seekp( 0, ios_base::cur )
  • ostringstream() .写( "", 0 )
  • ostringstream() .冲洗()
  • ostringstream() <<冲洗
  • ostringstream() <<nounitbuf
  • ostringstream() <<unitbuf
  • ostringstream() <<noshowpos
  • 或任何其他标准操纵器.[#include ] 参考:请参阅本网页下方 1/3 处的按格式插入数据".

我们不能使用:

  • operator<<( ostringstream(), "" )
  • (ostream &) ostringstream()

附加:现在很简单.

Appending: Straightforward now.

转换回来:我们可以只使用 (ostringstream&).但是 dynamic_cast 会更安全.在不太可能发生的事件 dynamic_cast 返回 NULL(它不应该),下面的 .str() 将触发核心转储.

Converting back: We could just use (ostringstream&). But a dynamic_cast would be safer. In the unlikely event dynamic_cast returned NULL (it shouldn't), the following .str() will trigger a coredump.

调用 str(): 猜.

把它们放在一起.

#define FORMAT(ITEMS)                                             
  ( ( dynamic_cast<ostringstream &> (                             
         ostringstream() . seekp( 0, ios_base::cur ) << ITEMS )   
    ) . str() )

<小时>

参考文献:


References:

  • IOstream 库
  • ostringstream
  • ostream::operator<<()

  • 类型转换教程
  • 维基:类型转换

.

相关文章