在Ruby等某些语言中,有一种用于创建格式化输出的精美语法 作为“一线”,部分原因是因为Ruby应用程序需要这样做。
在某些C ++应用程序中也经常需要它。这是一些示例代码:
if (num_doggies > num_biscuits) {
std::ostringstream ss;
ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!";
log_warn(ss.str());
this->negotiate_biscuit_reduction();
}
一些开源C ++ 98项目的解决方法如下所示:
struct string_formatter {
std::ostringstream ss;
template <typename T>
string_formatter & operator << (const T & t) {
ss << t;
return *this;
}
operator std::string() const {
return ss.str();
}
};
这样他们就可以这样写:
if (num_doggies > num_biscuits) {
log_warn(string_formatter{} << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!");
this->negotiate_biscuit_reduction();
}
将三条线转换成一条线。
然而,从代码审查的角度来看,string_formatter
类看起来相当邪恶,
主要是因为这种隐式转换。通常会考虑隐式转换
非常邪恶,当他们转变为普通或原始类型时,他们更邪恶
例如int
或std::string
。
在C ++ 11中,我们可以稍微改变一下:
operator std::string() && {
return ss.str();
}
现在转换只会在string_formatter
是r值引用时触发。
因此触发的可能性较小,但也更复杂。它真的不那么邪恶吗?
有争议的。
另外值得一提的是:其他人已经采用了更加精细的黑客技术来实现这一目标
没有string_formatter
垫片:https://codereview.stackexchange.com/questions/6094/a-version-of-operator-that-returns-ostringstream-instead-of-ostream
这里没有隐式转换,但是我们在标准库类型上重载运算符,这通常是禁止的。
让我们稍微回顾一下。为什么我不妥协并做到这一点?它至少要紧凑一点:
if (num_doggies > num_biscuits) {
std::ostringstream ss;
log_warn((ss << "There are " << num_doggies" << " puppy dogs and only " << num_biscuits << " biscuits!").str());
this->negotiate_biscuit_reduction();
}
事实证明这不会编译,因为std::ostringstream::operator <<
返回std::ostream &
而不是
std::ostringstream &
。当所有<<
都已解决时,我们只有一个ostream &
,因此我们无法使用.str()
。
我的问题是,为什么会这样?
为什么std::ostringstream::operator <<
没有返回std::ostringstream &
?是吗:
std::ostringstream &
转换为std::ostream &
吗?)注意:我很清楚设计string_formatter
和记录器类的不同方法。我特别感兴趣的是标准库中是否存在设计原因使得std::ostringstream
更好地返回std::ostream &
。
答案 0 :(得分:0)
如果您可以简化处理记录警告消息的代码,那么从您的帖子中就不清楚您是否会关心operato<<
函数返回的内容。
这是一种可以简化记录警告消息的代码的方法。
#include <iostream>
#include <sstream>
#include <string>
void log_warn(std::string const& s)
{
std::cout << s;
}
struct log_warning_impl
{
mutable std::ostringstream ss;
~log_warning_impl()
{
log_warn(ss.str());
}
};
template <typename T>
log_warning_impl const& operator<<(log_warning_impl const& l, const T & t)
{
l.ss << t;
return l;
}
log_warning_impl const& operator<<(log_warning_impl const& l, std::ostream&(*f)(std::ostream&))
{
l.ss << f;
return l;
}
#define WARNING_LOGGER log_warning_impl{}
int main()
{
WARNING_LOGGER << "There is a problem in the " << 10 << "-th line of the data file" << std::endl;
}
在您的情况下,您只需使用:
if (num_doggies > num_biscuits)
{
WARNING_LOGGER << "There are " << num_doggies << " puppy dogs and only " << num_biscuits << " biscuits!";
}