Использование std :: tie в качестве диапазона для цели цикла

Я хочу сделать что-то вроде следующего:

//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
TypeA a;
TypeB b;

for (std::tie(a, b) : someInitializingFunction()) {
// do stuff;
}
}

Однако это недопустимый код, поскольку, как говорится в стандарте, диапазон, основанный на цикле, определяется как эквивалентный:

{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}

Где объявление диапазона определяется как:

для диапазона декларирования:
атрибут-спецификатор-seq_ {opt} decl-спецификатор-seq декларатор

Что меня сдерживает, так это то, что decl-specier-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;
}
}

Но синтаксически это выглядит немного беспорядочно, поскольку интуитивно кажется довольно распространенной задачей, распаковывая результат вызова функции, что допустимо во многих других контекстах.

Есть ли предложение добавить что-то это к языку? Это даже разумная идея? Есть ли лучший способ сделать это, что я пропускаю? Я неправильно понимаю стандарт?

Очевидно, я мог бы собрать свою собственную функцию, чтобы сделать это, но это также немного грязно, чтобы использовать также.

22

Решение

Вы все еще можете использовать диапазон для!

//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.

При этом у вас нет возможности перемещать значения элементов в связанные переменные, так как begin(), end()и т. д. из контейнера r-значения не будут создавать итераторы перемещения. (Ну, да, вы можете адаптировать контейнер к чему-то, что возвращает итераторы перемещения, но это была бы совершенно новая история)

14

Другие решения

По состоянию на 03-21-2017 структурированные привязки являются частью C ++.

Это позволяет напрямую делать следующее:

//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
for (auto [a, b] : someInitializingFunction()) {
// do stuff;
}
7

По вопросам рекламы [email protected]