将矢量拆分为值

时间:2016-07-07 15:33:35

标签: c++ performance c++11

假设我有一个来自标记化函数tokenize()的值向量。我知道它只有两个值。我想将第一个值存储在a中,将第二个值存储在b中。在Python中,我会这样做:

a, b = string.split(' ')

我可以用丑陋的方式做到这一点:

vector<string> tokens = tokenize(string);
string a = tokens[0];
string b = tokens[1];

但这需要两行额外的代码,一个额外的变量和更低的可读性。

我如何以干净有效的方式在C ++中做这样的事情?

编辑:我必须强调效率非常重要。太多的答案不能满足这一要求。这包括修改my tokenization function

编辑2 :我使用C ++ 11是出于我无法控制的原因,我也无法使用Boost。

3 个答案:

答案 0 :(得分:3)

使用结构化绑定(肯定会在C ++ 17中),您可以编写如下内容:

auto [a,b] = as_tuple<2>(tokenize(str));

其中as_tuple<N>是一个将vector<string>转换为tuple<string, string, ... N times ...>的待声明函数,如果尺寸不匹配则可能会抛出。您无法对std::vector进行解构,因为它的大小在编译时是不可知的。这必然会对string进行额外的移动,因此您会失去一些效率以获得一些代码清晰度。也许没关系。

或许你写一个tokenize<N>直接返回tuple<string, string, ... N times ...>,避免额外的移动。在那种情况下:

auto [a, b] = tokenize<2>(str);

很棒。

在C ++ 17之前,你所拥有的就是你能做的。但是只需要引用变量:

std::vector<std::string> tokens = tokenize(str);
std::string& a = tokens[0];
std::string& b = tokens[1];

是的,它还有几行代码。这不是世界末日。这很容易理解。

答案 1 :(得分:2)

如果你“知道它只有两个值”,你可以这样写:

#include <cassert>
#include <iostream>
#include <string>
#include <tuple>

std::pair<std::string, std::string> tokenize(const std::string &text)
{
  const auto pos(text.find(' '));
  assert(pos != std::string::npos);

  return {text.substr(0, pos), text.substr(pos + 1)};
}

你的code是STL力量的一个很好的例子,但它可能有点慢。

int main()
{
  std::string a, b;

  std::tie(a, b) = tokenize("first second");

  std::cout << a << " " << b << '\n';
}

不幸的是,如果没有structured bindings(C ++ 17),您必须使用std::tie黑客,并且必须存在变量ab

答案 2 :(得分:0)

理想情况下,您需要重写tokenize()函数,以便它返回一对字符串而不是向量:

std::pair<std::string, std::string> tokenize(const std::string& str);

或者你将两个对空字符串的引用作为参数传递给函数。

void tokenize(const std::string& str, std::string& result_1, std::string& result_2);

如果您无法控制tokenize函数,那么您可以做的最好的方法是以最佳方式将字符串移出向量。

std::vector<std::string> tokens = tokenize(str);
std::string a = std::move(tokens.first());
std::string b = std::move(tokens.last());