2016-08-16 5 views
0

У меня есть m ints и n floats, и я хочу перебирать их в одном цикле. Для того, чтобы сделать это, я могу думать о двух возможных способах, но я не знаю, если они на самом деле выполнимы:C++ итерация по массивам разных типов

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

  2. Если я должен хранить int и плавать в двух массивах, есть ли (или как писать) итератор, который может перебирать два массива в цикле?

Любая идея приветствуется!

+0

вы можете использовать 'any' хранить их, но вы должны были бы иметь переменные маркера, чтобы знать, где начать читать Интс и где, чтобы начать читать поплавки, просто поместив их в двух массивах будет си mpler. –

+2

Почему вы хотите повторить их в одном цикле? –

+1

Я хочу повторить их в одном цикле, потому что это сделает мою оригинальную программу более кратким, поскольку она делает то же самое независимо от типа данных – pumpkinjuice

ответ

2

Кажется, шаблон функции может быть хорошим решением:

  1. сохраняет семантику «делает то же самое для обоих контейнеров поплавков и контейнеров Интс», без создания искусственного контейнера поплавки/Интс ради экономии нескольких строк кода
  2. с точки зрения производительности не будет никакой разницы с ручным закодированы итерации огибать обоих массивов, если вы включите оптимизаций компилятора -O3
  3. он будет работать для других типов (например, double, int64_t, int32_t и т.д.)

Это будет выглядеть следующим образом:

template<typename T> 
void processData(std::vector<T> data) { 
    for (auto& d : data) { 
    // do some processing 
    } 
} 

вы могли бы назвать его:

processData(std::vector<float>{1.2, 2.5, 3.5, 4.5}); 
processData(std::vector<int>{1, 2, 3, 4}); 

увидеть working example here

0

Либо создать на структуру и использовать его в качестве массива:

struct my_compund_type { 
    int integer; 
    float very_narrow_and_possibly_I_meant_double_float; 
}; 

std::vector<my_compund_type> array; 

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

+1

Это работает только в случае m == n. Особенно, если два значения логически не являются парами (т. Е. Они не принадлежат друг другу), это было бы очень вводящим в заблуждение решением ... –

2

Есть несколько варианты со всеми их различными преимуществами и недостатками:

  1. Используйте два std :: vector, один для другого для float и повторите их в отдельных циклах. Если тело цикла нетривиально, поместите его в шаблонную функцию, поэтому вам не нужно дублировать код.

  2. Используйте std :: vector boost :: any, который может хранить как float, так и ints. Когда вы приобретаете значение, вам нужно «отличить» его до нужного типа. Опять же, вы можете включить любую логику в шаблонную функцию, чтобы избежать дублирования кода. Поскольку boost :: any cast to the actual type включает проверку типов, это решение не имеет оптимальной производительности. С другой стороны, он приближается к поведению языков, типизированных во время выполнения, таких как Python.

  3. Особенно, если у вас есть более двух типов: используйте boost :: fusion :: map типа (float и int) для вектора типа.Вы можете выполнить итерацию карты с помощью boost :: fusion :: foreach, которая вызовет шаблонную функцию и передаст ей векторы. Таким образом, вы получаете по сути первое решение, но на этот раз оно масштабируется для многих типов данных.

Поскольку C++ статически типизирован, нет никакого способа иметь один контейнер, содержащий как float, так и ints без boost :: any. Исключение: если количество записей фиксировано во время компиляции, вам может помочь boost :: mpl :: vector.

Edit: Если вы хотите, примеры кода, дают использовать больше информации, которая, как вы хотите идти ...

1

Вы можете факторизовать код по-разному, например:

struct MyData { 

    template <typename FUNC> 
    void run(FUNC func) { 
     for (auto& i : ints) { 
       func(i); 
     } 
     for (auto& f : floats) { 
       func(f); 
     } 
    } 

    std::vector<int> ints; 
    std::vector<floats> floats; 
}; 

А потом, использование похоже на

MyData myData = /**/; 

myData.run([](auto e){ std::cout << e << " "; }); 
Смежные вопросы