我希望能够做到:
foo(stringstream()<<"number = " << 500);
编辑:单线解决方案至关重要,因为这是用于记录目的。这些将围绕代码。
在foo里面会将字符串打印到屏幕或类似的东西。
现在因为stringstream的运算符&lt;&lt;返回ostream&amp;,foo的签名必须是:
foo(ostream& o);
但是如何转换ostream&amp;串? (或char *)。 实现此用例的不同方法也是受欢迎的。
答案 0 :(得分:5)
显而易见的解决方案是在dynamic_cast
中使用foo
。但是给定的
代码仍然无法正常工作。 (你的例子将编译,但它不会做什么
你认为它应该。)表达式std::ostringstream()
是一个
临时的,你不能用临时的初始化非const引用,
和std::operator<<( std::ostream&, char const*)
的第一个参数
是一个非const引用。 (你可以调用一个成员函数
临时。像std::ostream::operator<<( void const* )
一样。所以代码
将编译,但它不会做你期望的。
您可以使用以下内容解决此问题:
foo( std::ostringstream().flush() << "number = " << 500 );
std::ostream::flush()
返回非const引用,因此没有
进一步的问题在新创建的流上,它是一个无操作。
不过,我认为你会同意它不是最优雅或最直观的
溶液
在这种情况下我通常做的是创建一个包装类
包含它自己的std::ostringstream
,并提供模板化
成员 operator<<
转发给所包含的人
std::ostringstream
。您的函数foo
将占用const
引用这个 - 或者我做的是有析构函数调用
直接foo
,以便客户端代码甚至不必担心
它;它的确如下:
log() << "number = " << 500;
函数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;
}
};
请注意,扩展它以便支持可选日志记录很容易;只是
为LogWrapper提供一个构造函数,用于将collector
设置为
NULL
,并在operator<<
。
编辑:
另一件事发生在我身上:你可能想检查一下
析构函数是由异常调用而不是调用
在这种情况下foo
。从逻辑上讲,我希望你唯一的例外
可能得到的是std::bad_alloc
,但总会有一个用户
写道:
log() << a + b;
其中+
是用户定义的重载抛出。
答案 1 :(得分:3)
您可以使用代理对象;这是一个框架,但如果你想在很多地方使用这种表示法,那么它可能是值得的:
#include <iostream>
#include <sstream>
static void foo( std::string const &s )
{
std::cout << s << std::endl;
}
struct StreamProxy
{
std::stringstream stream;
operator std::string() { return stream.str(); }
};
template <typename T>
StreamProxy &operator<<( StreamProxy &s, T v )
{
s.stream << v;
return s;
}
static StreamProxy make_stream()
{
return StreamProxy();
}
int main()
{
foo( make_stream() << "number = " << 500 );
}
此程序打印
number = 500
这个想法是有一个小的包装类,可以隐含地转换为std::string
。 <<
运算符只是转发到包含的std::stringstream
。 make_stream()
函数严格来说没有必要(你也可以说StreamProxy()
,但我觉得它看起来好一些。
答案 2 :(得分:3)
我建议你使用这个实用程序结构:
struct stringbuilder
{
std::stringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator std::string() { return ss.str(); }
};
并将其用作:
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 ;
}
演示(仅举几例):http://ideone.com/J995r
答案 3 :(得分:1)
在标头中定义一个静态字符串流变量,用于定义日志记录功能,并在调用日志记录函数时使用逗号运算符,以便传递此变量而不是流返回的ostream&
插入操作符。您可以使用日志记录宏来隐藏这种丑陋。这个解决方案的问题在于它有点丑陋,但这是一种常用的日志记录方法。
不要使用C ++ I / O.请改用varargs C风格的解决方案。传递格式字符串作为第一个参数,其余参数是该格式字符串的目标。此解决方案的一个问题是,即使您的编译器足够智能以确保printf
及其表兄弟是安全的,编译器可能也不会知道此新函数是printf
系列的一部分。尽管如此,这也是一种常用的方法。
答案 4 :(得分:1)
如果您不介意使用宏功能,可以使记录功能接受const string&
,并使用以下宏
#define build_string(expr) \
(static_cast<ostringstream*>(&(ostringstream().flush() << expr))->str())
假设您foo
有签名void foo(const string&)
,您只需要一行
foo(build_string("number = " << 500))
这是受到James Kanze关于static_cast
和stringstream.flush
的回答的启发。如果没有.flush()
,则上述方法会因意外输出而失败。
请注意,此方法不应泄漏内存,因为临时值(无论是否为指针形式)仍然在堆栈上分配,因此在返回时会被破坏。
答案 5 :(得分:0)
因为你要转换成字符串,为什么不呢
void foo(const std::string& s)
{
std::cout << "foo: " << s << std::endl;
}
...
std::stringstream ss;
ss << "number = " << 500;
foo(ss.str());
答案 6 :(得分:0)
这是不可能的。正如名称ostream
所暗示的那样,它用于输出,用于写入。您可以将参数更改为stringstream&
。此类的方法str()
会返回std::string
供您使用。
编辑我没有看到operator <<
返回ostream&
的问题。所以我想你不能简单地在函数参数列表中编写你的语句,但必须先编写它。
答案 7 :(得分:0)
您可以在std::ostringstream
周围创建一个小包装器,在使用时将转换回std::string
,并使该功能采用std::string const &
。这个解决方案的第一种方法可以在answer中找到另一个问题。
最重要的是,如果需要,您可以添加对操纵器(std::hex
)的支持。