2016-07-21 2 views
10

Предположим, что у меня есть 2 (или более) контейнеров хочу перебирать одновременно - например, чтобы вычислить скалярное произведение двух векторов:Диапазон для цикла с несколькими контейнерами

std::vector<double> vector1; 
std::vector<double> vector2; // identical size to vector1 

Что является предпочтительным С + +11 способ задать цикл диапазона для обоих (или всех) контейнеров одновременно? Включает ли это выбор одного контейнера/итератора для записи короткого замыкания (т. Е. for (auto i : c)) в цикле диапазона, в то время как все остальные контейнеры/итераторы должны обрабатываться долго? Есть ли какая-либо причина синтаксис в будущем не может быть расширен для поддержки стенографии для обоего/всех контейнеров, как показано ниже ..., который, кажется, действительно читает:

double dotProduct(0.0); 
for (auto const & value1 : vector1, auto const & value2 : vector2) // illegal! 
{ 
    dotProduct += value1*value2; 
} 
+3

Возможный дубликат [Каков наилучший способ повторения двух или более контейнеров одновременно] (http://stackoverflow.com/questions/12552277/whats-the-best-way-to-iterate-over-two-or -более-контейнеры одновременно) – ildjarn

+0

На первый взгляд, да ... но есть ли какие-либо ответы там (а), читаемые и (б) общие и (в) на основе стандартного C++? Не то, чтобы я видел. С первых дней C можно было написать 'for (i = 0, j = 0, k = 0; i omatai

+0

Посмотрите на [miterator] (https://github.com/ClaasBontus/miterator). Все станет проще с диапазонами, которые не будут до C++ 20. –

ответ

7

В других (часто функциональном) языках это делается используя функцию zip. В качестве примера, Python имеет встроенный почтовый индекс, который перебирает над своими аргументами и возвращает кортеж:

for i in zip([1,2,3], (1,2,3), { 0:0, 1:1, 2:2 }): 
    l,t,d = i 
    print("list item: %d, tuple item %d, dict item %d" % (l,t,d))  

Вы можете использовать библиотеку диапазона в C++, чтобы получить эту функциональность, например, Boost.Range или Eric Niebler's rangev3. К сожалению, в стандарте C++ 17 рейтинги, к сожалению, не голосовали, но я бы никогда не начал проект без библиотеки диапазонов. В Boost.Range функция называется combine:

#include <boost/range/combine.hpp> 
#include <iostream> 
#include <vector> 
#include <list> 

int main(int, const char*[]) 
{ 
    std::vector<int> const v{0,1,2,3,4}; 
    std::list<char> const l{'a', 'b', 'c', 'd', 'e'}; 

    for(auto const& i: boost::combine(v, l)) 
    { 
     int ti; 
     char tc; 
     std::tie(ti,tc) = i; 
     std::cout << '(' << ti << ',' << tv << ')' << '\n'; 
    } 

    return 0; 
} 

С C++ 17 вы можете заменить std::tie с структурировано связыванием и удаление рода необычной «инициализация» с std::tie.

for(auto const& [ti,tc] : boost::combine(v, l)) { 
    std::cout << '(' << ti << ',' << tv << ')' << '\n'; 
    } 

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

+0

Совершенно правильный ответ ... но, к сожалению, неутешительный. И не должно быть 'std :: tie (ti, tc) = i'? То, что я нахожу неудовлетворенным, не является вашей ошибкой - это ошибка синтаксиса C++, которая в значительной степени ориентируется на (a) объединение вещей с использованием (b) трюков и (c) одного итератора ... а не (более простого) нескольких синхронизированных итераторов , Учитывая исходный синтаксис Си, указанный в моем комментарии к моему вопросу, я удивлен, что C++ не поддерживает 'for (int i = 0, int j = 0; ...)', когда он поддерживает 'for (int i = 0, J = 0; ...) '. Мне любопытно узнать, есть ли веская причина, почему нет. – omatai

+0

@omatai, почему разочарование? Вы можете использовать boost :: combination даже в коде C++ 98. Что касается «трюков» - посмотрите на версию Python - есть также «трюк» для объединения вещей, даже у Haskell есть «трюк» zip.И я не думаю, что это недостаток - зачем загрязнять язык вещами, которые можно легко реализовать в библиотеках? –

+0

Считываемость, беспорядок. Если бы я натолкнулся либо на мой предложенный (незаконный) код, либо на этот код через пять лет, я бы сразу понял, что происходит с моим предложением, и мне нужно использовать гораздо больше возможностей и прыжков веры, чтобы переварить это (полностью действительное) версия (без обид @Jens). Поэтому я разочарован не в этом (полностью действительном) ответе, но в том, что синтаксис C++ не поддерживает то, что, по моему мнению, будет проще и чище. – omatai

Смежные вопросы