一个可变函数接受字符串和Ints,格式化后者并连接所有?

Par*_*duz 5 c++ variadic-functions variadic-templates c++11

我试图在这个问题中使用DanielKO的答案来满足我的需求,但我不熟悉模板和可变函数,我不知道该怎么办.

我需要的是一个可变的c ++(11)函数,我可以像这样调用:

 String NewMsg = CreateMessage("SET",16,1,17,0,"RED",47);
Run Code Online (Sandbox Code Playgroud)

并且NewMsg ="SET,0010,0001,0011,0000,RED,002F".

我甚至无法到达应该在参数之间添加逗号的位置.然后:在解析args时如何区分整数和字符串,以便将每个整数格式化为十六进制字符串?

Pas*_* By 8

您使用递归和函数重载

std::string CreateMessage(int i)
{
    return /* i formatted as hex */;
}

std::string CreateMessage(const char* s)
{
    return s;
}

template<typename T, typename... Ts>
std::string CreateMessage(T t, Ts... ts)
{
    return CreateMessage(t) + "," + CreateMessage(ts...);
}
Run Code Online (Sandbox Code Playgroud)


max*_*x66 2

混合其他两种解决方案(来自 Passer By 的递归解决方案和来自 Nick Mertin 的 C++17 折叠表达式),您CreateMessage()也可以在 C++11 中无需递归(以类似折叠表达式的方式)编写

std::string const & getStr (std::string const & ret)

 { return ret; }

std::string getStr (int val)
 {
   std::ostringstream ret;

   ret << std::hex << std::setw(4) << std::setfill('0') << val;

   return ret.str();
 }

template <typename ... Ts>
std::string CreateMessage (Ts const & ... args)
 {
   using unused = int[];

   std::string ret   = "";
   std::string comma = "";

   (void)unused { 0, ( ret += comma + getStr(args), comma = ",", 0 )... };

   return ret;
 }
Run Code Online (Sandbox Code Playgroud)

- 编辑 -

OP 询问

你想教我“相似折叠”线是如何工作的吗?我该如何“读”它?

嗯...该行如下

(void)unused { 0, ( ret += comma + getStr(args), comma = ",", 0 )... };
Run Code Online (Sandbox Code Playgroud)

其中unused是 的别名 ( using) int[]

它利用了可变参数包(模板或函数参数)可以在 C 风格数组初始化的上下文中进行扩展的事实,并且还使用了逗号运算符的强大功能(exec/compute 的逗号运算符的专有性并丢弃了在逗号的左边)。

args...所以你有(对于 中的每个参数)的扩展

( ret += comma + getStr(args), comma = ",", 0 )
Run Code Online (Sandbox Code Playgroud)

在哪里

1) 添加comma + getStr(args)ret, 其中第一个参数为空,以下参数comma等于(参见 (2))","

2)第一个逗号运算符丢弃值ret并分配","给(所以你在第一个和后面comma有一个空commaret +=","ret +=

3)第二个逗号运算符丢弃逗号的值并返回0到初始化unuses

Soret递增,所有getStr(args)数组均由分隔",",未使用的数组用零初始化。

观察另外几点:

a) 在数组(未命名unused)初始化列表中,有一个起始且与可变参数无关的零 ( { 0,);这是必要的,以防args...列表为空,因此该行变为(void)unsed { 0 };,这是合法的,而不是(void)unused { };(没有那个零)这是语法错误

b)unused前面是(void); 这并不是绝对必要的,但对于避免“对象已定义但未使用”类型的警告很有用。