如果`std :: ostringstream`有一个`运算符<<`返回`std :: ostringstream&`?

时间:2016-12-20 19:15:15

标签: c++ c++11 stream c++-standard-library c++98

在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类看起来相当邪恶, 主要是因为这种隐式转换。通常会考虑隐式转换 非常邪恶,当他们转变为普通或原始类型时,他们更邪恶 例如intstd::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 &

1 个答案:

答案 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!";
}