给自己的cout加上format

226 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

在之前的文章中,我也拙略的实现了一个简单得不像话的cout,现在,我们对已有的基础上,为cout这样的输出流加上一个format格式的功能!

为什么要这样做呢?

C++的输出用cout的话,我觉得并不算很好用,你要输出精度、十六进制、八进制等内容时,就非常痛苦面具了

那么,我们是不是可以给c++加一点插件呢?

比如要格式化某个东西的输出时这样做:

cout << format("this var is: %d%d", x, y) << x << " " << y << endl;

或者

cout << format("this var is: %d %d") << x << y << endl;

当然,我觉得如果这样设置还比不上直接用print

在不损失太多效率的情况下,支持一个混用的模式。

现在,让我们来看看如何实现:


首先

需要搞清楚的是,osteam的重载操作,要通过重载operator<<来做到,并且若是要访问fmt类的私有函数

则需要友元函数。

对于多个变量的传参问题,则可以使用模板可变长传参来实现参数转发问题。

然后把格式和参数交给sprintf来解决

于是,我们就可以写出第一版代码

class Fmt {
  static constexpr int BUFSIZE = {32};

private:
  char buf[BUFSIZE]{};

public:
  template <typename... Arg> Fmt(const char *fmt, Arg... arg) {
    sprintf(buf, fmt, arg...);
  }
  friend std::ostream &operator<<(std::ostream &os, const Fmt &fmt);
};
std::ostream &operator<<(std::ostream &os, const Fmt &fmt) {
  return (os << fmt.buf);
}

其实把fmt写成一个类有一点多余的嫌疑。

因为同意一个函数也可以做到这一件事情。

用函数则可以这样写:

template <typename... Arg>
const char* format(const char *fmt, Arg... arg) {
  char buf[BUFSIZ];
  sprintf(buf, fmt, arg...);
  return buf;
}

大概没有问题吧?

问题很大,若是这样写,局部变量就返回了!
生命周期发生变化,不要怪程序不听话~

但是,若是写出一个类的形式,其实可以在一定程度上避免这个问题(要不去试试上面那个程序有没有坑?)

当然,采用动态分配内存,这个就不存在了~

使用

下面,我们来看一看简单的使用:

int main() {
  std::cout << Fmt("%d %d\n", 1, 2)
            << Fmt("%s %c\n", "222", '1')
            << Fmt("%d %c", 1, 'A')
            << std::endl;
  return 0;
}

可以实现这种cout和format混用的场景,效率也不会损失太多。