【问题标题】:C++11 Equivalent to Boost.FormatC++11 等价于 Boost.Format
【发布时间】:2014-06-18 05:49:56
【问题描述】:

像 C++11 标准中的 Boost.Format 这样的东西吗?我已经能够避免使用具有更好 C++11 选项的 Boost 来满足我的所有其他需求。

就此而言,Boost.Format 无法比拟 Python format() 的语法。这样的东西会更好。

【问题讨论】:

  • 旧的 C/K&R xxprintf() 有什么问题?
  • 我喜欢它,但它不能直接接受string,这很烦人。我更喜欢不需要我在所有字符串上调用.c_str() 的方法。另外,它远没有 Python 的 format() 好。
  • @FoggyDay:没有类型安全。完全没有。零扩展性。

标签: c++ c++11 boost boost-format


【解决方案1】:

C++11、14 和 17 不提供类似的东西。

但是,C++20 提供了std::format,它在精神上与 Boost 格式相似,但其设计允许更高效的实现。 {fmt} library 是这个格式化工具的一个实现,它只需要 C++11:

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");

免责声明:我是 {fmt} 和 C++20 std::format 的作者

【讨论】:

    【解决方案2】:

    有一个类似于 boost-format 的提议。但是,它既不是 C++11 也不是 C++14 的一部分,也没有添加任何与字符串格式相关的内容。

    在这里您可以找到最新的提案。与 boost-format 相比,它基于可变参数模板。

    【讨论】:

      【解决方案3】:

      使用 c++11 正则表达式和可变参数模板实现类 Python 格式字符串函数。

      /**
         Helper code to unpack variadic arguments
      */
      namespace internal
      {
          template<typename T>
          void unpack(std::vector<std::string> &vbuf, T t)
          {
              std::stringstream buf;
              buf << t;
              vbuf.push_back(buf.str());
          }
          template<typename T, typename ...Args>
          void unpack(std::vector<std::string> &vbuf, T t, Args &&... args)
          {
              std::stringstream buf;
              buf << t;
              vbuf.push_back(buf.str());
              unpack(vbuf, std::forward<Args>(args)...);
          }
      }
      
      /**
          Python-like string formatting
       */
      template<typename ... Args>
      std::string format(const std::string& fmt, Args ... args)
      {
          std::vector<std::string> vbuf;  // store arguments as strings
          std::string in(fmt), out;    // unformatted and formatted strings
          std::regex re_arg("\\{\\b\\d+\\b\\}");  // search for {0}, {1}, ...
          std::regex re_idx("\\b\\d+\\b");        // search for 0, 1, ...
          std::smatch m_arg, m_idx;               // store matches
          size_t idx = 0;                         // index of argument inside {...}
      
          // Unpack arguments and store them in vbuf
          internal::unpack(vbuf, std::forward<Args>(args)...);
      
          // Replace all {x} with vbuf[x]
          while (std::regex_search(in, m_arg, re_arg)) {
              out += m_arg.prefix();
              auto text = m_arg[0].str();
              if (std::regex_search(text, m_idx, re_idx)) {
                  idx = std::stoi(m_idx[0].str());
              }
              if(idx < vbuf.size()) {
                  out += std::regex_replace(m_arg[0].str(), re_arg, vbuf[idx]);
              }
              in = m_arg.suffix();
          }
          out += in;
          return out;
      }
      

      示例:cpp.sh/9cvtz

      【讨论】:

      • 当我通过标头包含模板并使用 C++11 调用格式时,我收到“使用已删除函数”错误。请给我一些帮助好吗?
      • 好的,你能提供一个重现错误的sn-p吗?
      • 我将在明天提出一个问题并链接到它。但无论如何:要产生此错误,只需将 2 个模板放在头文件中并将其包含在 main.xml 中即可。这应该足够了。但我明天会详细检查。
      • 好的,当处理一个最小的例子时,结果证明,代码甚至没有在其他在线编译器中编译,也没有在 g++ 中编译。这是一个例子:onlinegdb.com/rJNMvHDNv
      • 我明白了,regex_search 不再允许使用临时字符串,所以在调用regex_search 之前添加:auto tmp = m_arg[0].str(); 并将tmp 作为第一个参数传递。
      【解决方案4】:

      使用 sprintf

      • 对于 C++20,使用 std::format
      • 有来自 C++11 版本的 fmt-library
      • 格式化输出的一些简单解决方案是printf
      • 要使用printf语法写一个std::string,使用下面的sn -p

      最小可重现示例:使用 printf 语法格式化 std::string

      interactive version

      #include <iostream>
      #include <string>
      #include <stdio.h>
      #include <assert.h>
      
      
      template<typename... Args>
      std::string fmt_str(std::string fmt, Args... args)
      {
          size_t bufferSize = 1000;
          char *buffer = new char[bufferSize];
          int n = sprintf(buffer, fmt.c_str(), args...);
          assert (n >= 0 and n < (int) bufferSize - 1  && "check fmt_str output");
      
          std::string fmtStr (buffer);
          delete buffer;
          return fmtStr;
      }
      
      
      
      int main()
      {
          int a=1, b=2;
          double c=3.;
          std::cout << fmt_str("%d plus %d is %f", a, b, c) << std::endl;
          return 0;
      }
      

      输出

      1 plus 2 is 3.000000
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-10
        • 1970-01-01
        • 2016-11-29
        • 2021-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多