C++ 如何从std::vector构造std::string<;字符串>;?

C++ 如何从std::vector构造std::string<;字符串>;?,c++,stl,string-concatenation,stringstream,stdstring,C++,Stl,String Concatenation,Stringstream,Stdstring,我想从std::vector构建一个std::string 我可以使用std::stringsteam,但想象一下有一种更短的方法: std::string string_from_vector(const std::vector<std::string> &pieces) { std::stringstream ss; for(std::vector<std::string>::const_iterator itr = pieces.begin();

我想从
std::vector
构建一个
std::string

我可以使用
std::stringsteam
,但想象一下有一种更短的方法:

std::string string_from_vector(const std::vector<std::string> &pieces) {
  std::stringstream ss;

  for(std::vector<std::string>::const_iterator itr = pieces.begin();
      itr != pieces.end();
      ++itr) {
    ss << *itr;
  }

  return ss.str();
}
std::string string_from_vector(const std::vector&pieces){
std::stringstream-ss;
对于(std::vector::const_迭代器itr=pieces.begin();
itr!=碎片。结束();
++itr){
ss您可以使用
标题中的标准函数(其工作原理是为
字符串
定义了
运算符+
重载,返回其两个参数的串联):


为什么不直接使用operator+将它们添加到一起

std::string string_from_vector(const std::vector<std::string> &pieces) {
   return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}
std::string string_from_vector(const std::vector&pieces){
返回std::accumulate(pieces.begin()、pieces.end()、std::string(“”);
}

STD::Stand使用默认的STD::加上两个字符串,在C++中加上,因为操作符+重载STD::/P>< P>用C++ 11,<强> String Strue方法不太吓人:

#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iostream>

int main()
{
    std::vector<std::string> v{"Hello, ", " Cruel ", "World!"};
   std::stringstream s;
   std::for_each(begin(v), end(v), [&s](const std::string &elem) { s << elem; } );
   std::cout << s.str();
}
#包括
#包括
#包括
#包括
#包括
int main()
{
向量v{“你好”,“残忍”,“世界!”;
std::strings;
std::for_each(begin(v)、end(v),[&s](const std::string&elem){s C++03
std::字符串s;
对于(std::vector::const_迭代器i=v.begin();i!=v.end();++i)
s+=*i;
返回s;
C++11(MSVC 2010子集)
std::字符串s;
std::for_each(v.begin()、v.end()、[&](const std::string&piece){s+=piece;});
返回s;
C++11
std::字符串s;
对于(常数自动和工件:v)s+=工件;
返回s;
不要使用
std::acculate
进行字符串连接
,这是一个经典,甚至比C中使用
strcat
的常见示例更糟糕。如果没有C++11移动语义,向量的每个元素都会产生两个不必要的累加器副本。即使使用移动语义,也会产生一个不必要的累加器副本每个元件的蓄能器

上面的三个例子是O(n)

std::accumulate
对于字符串是O(n²)

通过提供一个 自定义函子:

std::string s = std::accumulate(v.begin(), v.end(), std::string{},
    [](std::string &s, const std::string &piece) -> decltype(auto) { return s += piece; });
请注意,
s
必须是对非常量(lambda返回类型)的引用 必须是引用(因此
decltype(auto)
),正文必须使用
+=
不是
+

C++20 在C++20的当前草案中,
std::acculate
的定义是在附加到累加器时使用
std::move
,因此从C++20开始,
acculate
O(n)用于字符串,并且可以用作一行程序:

std::string s = std::accumulate(v.begin(), v.end(), std::string{});

我个人的选择是基于范围的for循环,如中所示

Boost还提供了一个很好的解决方案:

#include <boost/algorithm/string/join.hpp>
#include <iostream>
#include <vector>

int main() {

    std::vector<std::string> v{"first", "second"};

    std::string joined = boost::algorithm::join(v, ", ");

    std::cout << joined << std::endl;
}
#包括
#包括
#包括
int main(){
向量v{“第一”、“第二”};
std::string join=boost::algorithm::join(v,“,”);

std::cout晚会有点晚,但我喜欢我们可以使用初始值设定项列表的事实:

std::string join(std::initializer_list<std::string> i)
{
  std::vector<std::string> v(i);
  std::string res;
  for (const auto &s: v) res += s;
  return res;   
}

Google Abseil有函数absl::StrJoin,可以满足您的需要

他们文件中的示例。 请注意,分隔符也可以是“

//std::vector v={“foo”、“bar”、“baz”};
//std::string s=absl::StrJoin(v,“-”);
//预期均衡器(“foo-bar-baz”,s);

如果不需要尾随空格,请将
中定义的
累积
与自定义联接lambda一起使用

#包括
#包括
#包括
使用名称空间std;
int main(){
向量v;
字符串s;
v、 推回(字符串(“费用”);
v、 向后推(字符串(“fi”);
v、 向后推(字符串(“foe”);
v、 向后推(字符串(“fum”);
s=累加(开始(v)、结束(v)、字符串(),
[](字符串lhs,常量string&rhs){返回lhs.empty()?rhs:lhs+''+rhs;}
);

对于(…){res+=*it;}
?可爱但粗心。它将为每个操作分配一个新字符串,因为它使用
运算符+
并生成一个新字符串,而不是
运算符+=
来修改现有的字符串。我编写了一个库,它将使用
s=v | sum();
内部使用
+=
而不是
+
;-)@BenjaminLindley实际上并不适用于每个,因为大多数实现仅两倍于每个realloc+1使用free begin()end()的能力而不是.begin.end成员函数。@PSIAlt:再次读取它,它会为每个操作分配一个新字符串,因为每个操作都会生成一个新字符串。倍增大小优化不会影响这一点。BenjaminLindley:他说的是字符串如何“倍增”当你在里面放太多的时候,它就是容量。我会把函数命名为
to_string
,而不是
string\u from_vector
。我可能也会,但这是原始问题中使用的名称。为什么不使用
for(auto&I:v){s为什么还要使用stringstream呢?将
s
设为字符串,并将lambda
{s+=elem}
@Oktalist no!这是Schlemiel the painter悲观化的教科书示例。@v.oddou它不是Schlemiel the painter,因为
std::string
知道它自己的长度。它不必迭代
s
来找到空终止符。不过,可以通过使用
std::string::reserve
来改进它,以避免重复
s
的分配。另请参见上面我的得票最多(但未被接受)的答案。@Oktalist ok显然在考虑end()-begin()时是有保证的所以不要介意我的废话。为什么你要用
std::initializer\u list
而不是
std::vector
?另外,我认为你不需要复制向量,这样就可以通过常量引用传递。@jb initlist或vectors都是错误的。处理集合的函数应该包含范围。通过应用
#include <boost/algorithm/string/join.hpp>
#include <iostream>
#include <vector>

int main() {

    std::vector<std::string> v{"first", "second"};

    std::string joined = boost::algorithm::join(v, ", ");

    std::cout << joined << std::endl;
}
std::string join(std::initializer_list<std::string> i)
{
  std::vector<std::string> v(i);
  std::string res;
  for (const auto &s: v) res += s;
  return res;   
}
join({"Hello", "World", "1"})
//   std::vector<std::string> v = {"foo", "bar", "baz"};
//   std::string s = absl::StrJoin(v, "-");
//   EXPECT_EQ("foo-bar-baz", s);
fee fi foe fum