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<<()代码>
- 类型转换教程
- 维基:类型转换
.
相关文章