我希望能够做到:
foo(stringstream()<<"number = " << 500);
Run Code Online (Sandbox Code Playgroud)
编辑:单线解决方案至关重要,因为这是用于记录目的.这些将围绕代码.
在foo里面会将字符串打印到屏幕或类似的东西.
现在因为stringstream的运算符<<返回ostream&,foo的签名必须是:
foo(ostream& o);
Run Code Online (Sandbox Code Playgroud)
但是如何将ostream转换为字符串呢?(或char*).实现此用例的不同方法也是受欢迎的.
我建议您使用此实用程序结构:
struct stringbuilder
{
std::stringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator std::string() { return ss.str(); }
};
Run Code Online (Sandbox Code Playgroud)
并将其用作:
void f(const std::string & s );
int main()
{
char const *const pc = "hello";
f(stringbuilder() << '{' << pc << '}' );
//this is my most favorite line
std::string s = stringbuilder() << 25 << " is greater than " << 5 ;
}
Run Code Online (Sandbox Code Playgroud)
演示(还有几个例子):http : //ideone.com/J995r
更多关于我的博客:在一行中即时创建字符串
显而易见的解决方案是使用dynamic_cast在foo.但是给定的代码仍然不起作用.(你的例子将编译,但它不会做你认为应该做的.)表达式std::ostringstream()是临时的,你不能用临时初始化非const引用,并且第一个参数std::operator<<( std::ostream&, char const*)
是非const引用.(你可以在一个临时的.上调用一个成员函数std::ostream::operator<<( void const* ).所以代码会编译,但它不会做你期望的.
您可以使用以下方法解决此问题:
foo( std::ostringstream().flush() << "number = " << 500 );
Run Code Online (Sandbox Code Playgroud)
std::ostream::flush()返回一个非const引用,因此没有其他问题.在新创建的流上,它是一个无操作.不过,我认为你会同意它不是最优雅或最直观的解决方案.
在这种情况下我通常做的是创建一个包装类,它包含它自己的包装类std::ostringstream,并提供一个模板化的
成员 operator<<,它转发给包含的
std::ostringstream.你的函数foo会const
引用这个 - 或者我做的是foo直接调用析构函数
,这样客户端代码甚至不必担心它; 它做的事情如下:
log() << "number = " << 500;
Run Code Online (Sandbox Code Playgroud)
该函数log()返回包装类的实例(但见下文),该类的(最终)析构函数调用您的函数
foo.
这有一个小问题.可以复制返回值,并在复制后立即销毁.哪个会破坏我刚刚解释的内容; 事实上,既然std::ostringstream不可复制,它甚至不会编译.这里的解决方案是将所有实际逻辑(包括std::ostringstream析构函数和析构函数逻辑调用的实例)foo放在一个单独的实现类中,使公共包装器具有一个boost::shared_ptr转发器和转发器.或者只是在类中重新实现一些共享指针逻辑:
class LogWrapper
{
std::ostringstream* collector;
int* useCount;
public:
LogWrapper()
: collector(new std::ostringstream)
, useCount(new int(1))
{
}
~LogWrapper()
{
-- *useCount;
if ( *useCount == 0 ) {
foo( collector->str() );
delete collector;
delete useCount;
}
}
template<typename T>
LogWrapper& operator<<( T const& value )
{
(*collector) << value;
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,扩展它很容易支持可选的日志记录; 只需为LogWrapper提供一个构造函数,该构造函数设置collector为NULL,并在其中进行
测试operator<<.
编辑:
另一件事发生在我身上:你可能想要检查析构函数是否因异常而被调用,而不是foo在这种情况下调用
.从逻辑上讲,我希望你可能得到的唯一例外是std::bad_alloc,但总会有一个用户写下这样的东西:
log() << a + b;
Run Code Online (Sandbox Code Playgroud)
其中+是用户定义的重载抛出.