C ++格式的宏/内联ostringstream [英] C++ format macro / inline ostringstream

查看:203
本文介绍了C ++格式的宏/内联ostringstream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图编写一个宏,它允许我做一些类似于: FORMAT(a<<b< c< d),结果将是一个字符串 - 与创建ostringstream一样,插入 a ... d ,并返回。 STR()。像这样:

pre $ c $ string $
$
o<<一个< b<< c< d;
return o.str()
}

实际上, FORMAT(a <<b<< c< d)== f()



首先,我试过:

  1:#define FORMAT(items)\ 
((std :: ostringstream& amp; amp; ;)(std :: ostringstream()

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



  2:#define FORMAT( (std :: ostringstream())(std :: ostringstream()<<<<<\b'<<< items))。str()

给出了正确的输出,但是 0 \ b 出现在字符串当然。

以下似乎工作,但编译警告(以临时地址):

  3:#define FORMAT(items)\ 
((std: :ostringstream&)(*((std :: ostream *)(& std :: ostringstream()))<<< items))。str()
std :: string ?是不是1和3基本上是相同的?我怀疑,C ++ 0x可变参数模板将使格式(a,b, c,d)可能。但现在有没有办法解决这个问题呢? 解决方案

但是要遵循一点点挑战。所以,让我试着总结一下你所说的话...




这里的困难在于: p>


  • 我们正在玩一个临时的 ostringstream 对象,因为它是一个临时的,所以我们不能通过强制转换来转换为一个 ostream 对象。


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

  • 运算符<(lt;(...)既作为继承的 ostream 方法和全局功能。在任何情况下,它都会返回一个 ostream& 引用。

  • > ostringstream()<<foo< / code>是继承的方法 ostream :: operator<<(void *) 运算符<<(ostream&,const char *)。继承的 ostream ::运算符<<(void *)胜出,因为我们不能转换为 ostream 对象引用来调用全局函数。 [b] [b] [b] [b] [b] [b] [b] [b] [b] [b] [ >所以,要解决这个问题,我们需要:


    • 分配一个临时的 ostringstream
    • 将其转换为 ostream

    • 附加数据。

    • 将它转换回 ostringstream

    • 并调用 str()






    分配: ostringstream()


    $ b

    转换: 有几个选择。其他人则建议:

    $ b $ li $ ostringstream()<< std :: string()//对* David Norman的赞美*

  • ostringstream()<< std :: dec //授予* cadabra *



使用:



添加: 现在简单明了。

我们可以使用
code>(ostringstream&安培;)
。但 dynamic_cast 会更安全。在不太可能的情况下, dynamic_cast 返回 NULL (它不应该),下面的 .str ()会触发coredump。


$ b

调用 str() 猜猜。






放在一起。
$ b

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

参考文献: b
$ b




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()
}

Essentially, FORMAT(a << "b" << c << d) == f().

First, I tried:

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

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

This:

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

gives what seems like the right output, but the 0 and \b 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()

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?

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...


That difficulties here are that:

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

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

  • 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<<(...) exists as both inherited ostream methods and global functions. In all cases it returns an ostream& reference.

  • 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:

  • Allocate a temporary ostringstream.
  • Convert it to an ostream.
  • Append data.
  • Convert it back to an ostringstream.
  • And invoke str().

Allocating: ostringstream().

Converting: There are several choices. Others have suggested:

  • ostringstream() << std::string() // Kudos to *David Norman*
  • ostringstream() << std::dec // Kudos to *cadabra*

Or we could use:

We cannot use:

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

Appending: Straightforward now.

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.

Invoking str(): Guess.


Putting it all together.

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


References:

.

这篇关于C ++格式的宏/内联ostringstream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆