Итерация по ссылкам? - PullRequest
       19

Итерация по ссылкам?

6 голосов
/ 07 февраля 2012

Я хотел бы выполнить одну и ту же операцию над несколькими массивами, что-то вроде:

#include<vector>
#include<algorithm>
int main(void){
    std::vector<double> a, b;
    for(auto& ab:{a,b}) std::sort(ab.begin(),ab.end()); // error 
}

Этот код завершается ошибкой, поскольку auto& является константной ссылкой.Есть ли элегантный способ обойти это?

Ответы [ 3 ]

7 голосов
/ 07 февраля 2012

Я думаю, проблема в том, что это немного похоже на привязку временного к неконстантной ссылке.Там нет «конкретной» коллекции, поэтому она немного напоминает временную.

Если у вас есть временный вектор, он будет привязан к константной ссылке, но не к неконстантной.

Я также думаю, что это никогда не сработает, что вы делаете, но это должно сработать:

#include<vector> 
#include<algorithm> 
int main(void)
{     
    std::vector<double> a, b;     
    for(std::vector<double>* ab:{&a,&b}) 
      std::sort(ab->begin(),ab->end()); // or begin(*ab),end(*ab)
} 

и auto тоже может сработать.

2 голосов
/ 07 февраля 2012

Этот код не работает, , так как auto & является константной ссылкой. [выделение мое]

Ваши рассуждения не верны.В цикле for, основанном на диапазоне, то, что вы объявляете (здесь auto& ab), равно , а не , привязанному к выражению диапазона (здесь {a,b }).Вместо этого ab будет инициализироваться из элементов диапазона, а не самого диапазона.

Вместо этого ошибка связана с вызовом std::sort с параметрами ab.begin() / ab.end()Это легко можно увидеть, комментируя тело цикла.Как указал RMartinho, элементы std::initializer_list<std::vector<double>> являются неизменяемыми, и вы не можете отсортировать контейнер const (std::sort перетасовывает элементы, используя ходы, не может назначаться элементу const).

Предполагая, что вы хотите (независимо) отсортировать оба вектора, вы можете сделать:

for(auto& ab: { std::ref(a), std::ref(b) })
    std::sort(std::begin(ab.get()), std::end(ab.get()));

Обратите внимание, что согласно правилам вывода аргументов шаблона, auto& здесь хорошо, и auto будет выведенодо const std::reference_wrapper<std::vector<double>>, получая std::reference_wrapper<std::vector<double>> const& как тип ab.

0 голосов
/ 07 февраля 2012

Я думаю, решение CashCows - это хорошо.Просто чтобы показать другой способ: вы также можете использовать переменные шаблоны для решения этой проблемы.

#include <vector>
#include <algorithm>

using namespace std;

void mysort() {} // termination version

template<typename Arg1, typename... Args>
void mysort(Arg1 &arg1, Args&... args )
{
    sort(arg1.begin(), arg1.end());
    mysort(args...);
}

int main(void)
{
    vector<double> a, b;
    mysort(a, b);
}

@ CashCow: алгоритм можно передать в качестве аргумента, но он немного уродлив из-за использованияdecltype:

#include <vector>
#include <algorithm>

using namespace std;

template<typename Algo>
void mysort(Algo algo) {} // termination version

template<typename Algo, typename Arg1, typename... Args>
void mysort(Algo algo, Arg1 &arg1, Args&... args )
{
    algo(arg1.begin(), arg1.end());
    mysort(algo, args...);
}

int main(void)
{
    vector<double> a, b;
    mysort(&sort<decltype(a.begin())>, a, b);
}
...