我想做以下事情:
//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
TypeA a;
TypeB b;
for (std::tie(a, b) : someInitializingFunction()) {
// do stuff;
}
}
但是,这不是有效的代码,因为正如标准所说,基于for循环的范围被定义为等效于:
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
将for-range-declaration定义为:
换范围声明: attribute-specifier-seq_ {opt} decl-specifier-seq声明符
那么阻碍我的是decl-specifier-seq没有被标记为可选项?
因此,似乎我必须依靠旧式的循环来实现这个循环:
std::vector<std::pair<TypeA, TypeB>> myList = someInitializingFunction();
{
TypeA a;
TypeB b;
for (auto it = myList.begin(); it != myList.end(); ++it) {
std::tie(a, b) = *it;
// do stuff;
}
}
但是在语法上看起来似乎有些混乱似乎是一个相当常见的任务,解包函数调用的结果,这在许多其他上下文中都是有效的。
是否有建议将此内容添加到语言中?这是否合情合理?有没有更好的方法来做到这一点,我忽略了?我误读了标准吗?
显然,我可以将我自己的功能放在一起来做这件事,但是使用它也有点麻烦。
答案 0 :(得分:15)
您仍然可以使用range-for!
//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
TypeA a;
TypeB b;
for (auto& p : someInitializingFunction()) {
std::tie(a, b) = p;
// do stuff;
}
}
如果您不需要/想要修改const auto& p
,请p
。
更新:使用上述内容,您还可以使用std::move
for (auto& p : someInitializingFunction()) {
std::tie(a, b) = std::move(p);
// do stuff;
}
您的建议语法可能无法很好地处理。一个人为的例子:
for (std::tie(a, b) : std::move(someInitializingFunction())) {}
// Note: std::move here is superfluous, as it's already an r-value
// (may also hinder some optimizations). Purely for demonstration purposes.
有了这个,你就无法将元素的值移动到绑定变量,因为来自r值容器的begin()
,end()
等不会产生移动迭代器。 (嗯,是的,你可以将容器调整为返回移动迭代器的东西,但这将是一个全新的故事)
答案 1 :(得分:8)
截至2017年3月21日,结构化绑定是C ++的一部分。
这允许直接执行以下操作:
//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
for (auto [a, b] : someInitializingFunction()) {
// do stuff;
}