I want to do something like the following:
//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
TypeA a;
TypeB b;
for (std::tie(a, b) : someInitializingFunction()) {
// do stuff;
}
}
However, this is not valid code because, as the standard says, a range based for loop is defined as equivalent to:
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
Where a for-range-declaration is defined as:
for-range-declaration: attribute-specifier-seq_{opt} decl-specifier-seq declarator
So what's holding me back is that decl-specifier-seq is not marked as optional?
Therefore, it seems that I must fall back on old style for loops for this one a la:
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;
}
}
But it seems a bit messy syntactically for what seems to intuitively be a rather common task, unpacking the result of a function call, which is valid in many other contexts.
Is there a proposal to add something this to the language? Is this even reasonable idea? Is there a better way to do this that I'm overlooking? Am I misreading the standard?
Obviously, I could put together my own function to do this, but that's also a bit messy to use as well.
You can still use range-for!
//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
TypeA a;
TypeB b;
for (auto& p : someInitializingFunction()) {
std::tie(a, b) = p;
// do stuff;
}
}
Or const auto& p
if you don't need/want to modify p
.
UPDATE: With the above, you can also move the elements to the tied variables using std::move
for (auto& p : someInitializingFunction()) {
std::tie(a, b) = std::move(p);
// do stuff;
}
for which your proposed syntax may not handle well. A contrived example:
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.
With that, you don't have the ability to move the values of the elements to the tied variables, as begin()
, end()
, etc. from an r-value container won't produce move iterators. (Well, yes you could adapt the container into something that returns move iterators, but that would be a whole new story)