【问题标题】:Pass unknown type and quantity of args and concat to char array将未知类型和数量的 args 和 concat 传递给 char 数组
【发布时间】:2016-12-17 16:32:22
【问题描述】:

有没有办法将未知数量的 args(可以是 char 字符串或整数)传递给函数,然后将它们连接到 char 数组缓冲区?

例如,能够调用以下所有函数:

bufcat("this", 1, 3, "that");  
// buffer = "this13that"
bufcat(1, "this", "that", 3, 4000000, "other");
// buffer = "1thisthat34000000other"
bufcat(1000000,2,3,4,5,6,7,8,9,10,11,12,13,"onemillionandfiftytwo");
// buffer = "10000002345678910111213onemillionandfiftytwo"

【问题讨论】:

  • 试试看 va_args,这可以用 C 和 C++ 中的可变参数来完成
  • 不可能按照您定义的方式进行,否则printfscanf 不需要格式参数(当然您可以按照前面提到的函数定义的方式进行)。研究 C++ 中的运算符,它们可以用来执行此操作(可能有一个代理对象,它累积链接对象,然后可以转换为 std::string),尽管它可能看起来不太干净。但是话又说回来,为此拥有一个全局缓冲区并不是我所说的干净。
  • 确定至少需要一件事来定义参数的数量
  • 您应该能够使用可变参数模板来做到这一点。但为什么是 char 数组 而不是 std::string
  • 问题不在于参数的数量(va_arg 可以毫无问题地解决),而是参数的内容。您需要知道元素是什么类型(这就是当您的格式参数不正确时 printf/scanf 行为不端的原因)

标签: c++ arrays templates generics variadic-functions


【解决方案1】:

您可以使用可变参数模板加上字符串流:

template<typename... Args>
std::string bufcat(Args&&... args) {
    std::stringstream ss;

    auto iteration = [&ss](auto&& item) { ss << std::forward<decltype(item)>(item); };

    (void)std::initializer_list<int> {(
        iteration(std::forward<Args>(args))
    , 0)..., 0};

    return ss.str();
}

这会将您在参数中传递的任何内容连接到字符串流中。它将为Args 中的每个参数调用iteration lambda。

然后,您可以像这样简单地调用您的函数:

bufcat(1000000,2,3,4,5,6,7,8,9,10,11,12,13,"onemillionandfiftytwo");

它将产生10000002345678910111213onemillionandfiftytwo

【讨论】:

    【解决方案2】:

    在 c++11 中使用可变参数模板可以实现一个简单的解决方案。 如果性能很重要,经典 printf 习惯用法所需的样板代码可能比此处使用的内存分配更容易接受。

    #include <string>
    #include <iostream>
    inline std::string bufcat() { return ""; }
    template<typename value_type> std::string bufcat(const value_type &value)    { return std::to_string(value); }
    template<> std::string bufcat(const bool &b) { return b ? "true" : "false"; }
    std::string bufcat(const std::string &str) { return str; }
    std::string bufcat(const char *str) { return str; }
    template <typename arg0_type, typename ...arg_types>
    std::string bufcat(arg0_type arg0, arg_types ... args)
    { return bufcat(arg0).append(bufcat(args...)); }
    
    int main()
    {
        std::cout << bufcat(1000000,2,3,4,5,6,7,8,9,10,11,12,13,"onemillionandfiftytwo") << "\n";
    }
    

    【讨论】:

      猜你喜欢
      • 2013-07-26
      • 1970-01-01
      • 2021-12-02
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      • 2012-05-10
      相关资源
      最近更新 更多