一个接受Strings和Ints的变元函数,格式化后者并连接所有Ints



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

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

String NewMsg = CreateMessage("SET",16,1,17,0,"RED",47);

并具有NewMsg="SET,0010000100110000,RED,002F"。

我甚至不知道该在论点之间加逗号。然后:在解析参数时,我如何区分整数和字符串,以便将每个整数格式化为十六进制字符串?

使用递归和函数重载

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...);
}

一种选择是对模板使用递归,就像Passer By在回答中所做的那样。然而,在我看来,一个更优雅的解决方案(如果您能够使用C++17 lanugage特性)是使用fold表达式来避免递归。表达式被扩展为直接为每个参数调用Append,有点像编译时计算的参数之间的for循环。

template <class T>
void Append(std::ostringstream &out, T &&arg) {
out << "," << std::forward<T>(arg);
}
template <class... TArgs>
std::string CreateMessage(TArgs &&...args) {
std::ostringstream out;
(Append(out, std::forward<TArgs>(args)), ...);
return out.str().substr(1);
}

现场演示。

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

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;
}

--编辑--

OP询问

你愿意教我"相似折叠"线是如何工作的吗?我应该如何"阅读"它?

嗯。。。这条线是下面的

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

其中CCD_ 3是CCD_ 5的别名(using)。

它使用了可变包(模板或函数参数)可以在C样式数组初始化的上下文中展开的事实,还使用了逗号运算符的威力(exec/compute的逗号运算符的适当性,并丢弃逗号左侧的内容)。

所以你有的展开式(对于args...中的每个自变量)

( ret += comma + getStr(args), comma = ",", 0 )

其中

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

2) 第一个逗号运算符丢弃ret的值,并将","分配给comma(因此在第一个ret +=","中有一个空的comma用于后面的ret +=

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

因此,ret随着所有getStr(args)","分隔而递增,并且未使用的数组被初始化为零。

观察另外几点:

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

b)unused前面是CCD_;这不是严格必要的,但对于避免"对象已定义但未使用"类型的警告很有用。

相关内容

  • 没有找到相关文章

最新更新