因为我喜欢单行代码(正如您将在最后看到的,它们对于各种奇怪的东西都非常有用),所以这是一个使用std :: accumulate和C ++ 11 lambda的解决方案:
std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} )
我发现此语法对流运算符很有用,在这种情况下,我不想使所有奇怪的逻辑超出流操作的范围,而只是执行简单的字符串连接。例如,考虑以下方法的return语句,该方法使用流运算符(使用std;)格式化字符串:
return (dynamic_cast<ostringstream&>(ostringstream()
<< "List content: " << endl
<< std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} ) << endl
<< "Maybe some more stuff" << endl
)).str();
更新:
如@plexando在评论中所指出的,由于数组“空头”的检查遗漏了先前的空头,并且没有其他字符,因此上述代码在数组以空字符串开头时会出现错误行为。在所有运行中都检查“首次运行”是很奇怪的(即代码未优化)。
如果我们知道列表中至少包含一个元素,那么解决这两个问题就很容易。OTOH,如果我们知道该列表没有至少一个元素,那么我们可以缩短运行时间。
我认为生成的代码不太漂亮,因此我将其添加为“正确的解决方案”,但我认为上面的讨论仍然有其优点:
alist.empty() ? "" :
++alist.begin(), alist.end(),
*alist.begin(),
[](auto& a, auto& b) { return a + "," + b; });
笔记:
- 对于支持直接访问第一个元素的容器,最好将其用于第三个参数,
alist[0]
对于矢量来说更好。
- 根据评论和聊天中的讨论,lambda仍会进行一些复制。可以通过使用以下(不太漂亮的)lambda来最小化该值:
[](auto&& a, auto&& b) -> auto& { a += ','; a += b; return a; })
它(在GCC 10上)将性能提高了10倍以上。感谢@Deduplicator的建议。我仍在尝试弄清这里发生了什么。