如何从 std::vector<string> 构造 std::string?

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

I'd like to build a std::string from a std::vector<std::string>.

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

I could use std::stringsteam, but imagine there is a shorter way:

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

我还能怎么做?

推荐答案

C++03

std::string s;
for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i)
    s += *i;
return s;

C++11 (MSVC 2010 子集)

std::string s;
std::for_each(v.begin(), v.end(), [&](const std::string &piece){ s += piece; });
return s;

C++11

std::string s;
for (const auto &piece : v) s += piece;
return s;

不要使用std::accumulate进行字符串连接,这是一个经典的Schlemiel 画家的算法,甚至比在 C 中使用 strcat 的通常示例还要糟糕.如果没有 C++11 移动语义,它会导致两个不必要的副本向量的每个元素的累加器.即使使用移动语义,它仍然会为每个元素产生一个不必要的累加器副本.

Don't use std::accumulate for string concatenation, it is a classic Schlemiel the Painter's algorithm, even worse than the usual example using strcat in C. Without C++11 move semantics, it incurs two unnecessary copies of the accumulator for each element of the vector. Even with move semantics, it still incurs one unnecessary copy of the accumulator for each element.

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

std::accumulate 对于字符串是 O(n2).

您可以通过提供一个字符串来使 std::accumulate O(n)自定义函子:

You could make std::accumulate O(n) for strings by supplying a custom functor:

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)),并且主体必须使用+= 不是 +.

Note that s must be a reference to non-const, the lambda return type must be a reference (hence decltype(auto)), and the body must use += not +.

C++20

在预期成为 C++20 的当前草案中,std::accumulate 的定义是 改变在附加到累加器时使用 std::move,所以从 C++20 开始,accumulate 将是 O(n) 用于字符串,并且可以用作单行:

C++20

In the current draft of what is expected to become C++20, the definition of std::accumulate has been altered to use std::move when appending to the accumulator, so from C++20 onwards, accumulate will be O(n) for strings, and can be used as a one-liner:

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

相关文章