假设我有一个来自标记化函数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。
答案 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
黑客,并且必须存在变量a
和b
。
答案 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());