Допустим, у нас есть такая функция, где vec1 и vec2 хранят одинаковые данные:

int myFunc(vector& vec1, vector& vec2) {
    for (auto const& elem : vec1) {
        // do something
    }
    for (auto const& elem : vec2) {
        // do the same thing
    }
}

Очевидно, что дублирование кода - это не очень хорошо. Однако следующее не является решением:

int myFunc(vector& vec1, vector& vec2) {
    for (auto const& vec : {vec1, vec2}) {
        for (auto const& elem : vec) {
            // do something
        }
    }
}

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

Так как же сделать одно и то же с vec1 и vec2 без дублирования кода?

Tony

Ответы (3)

Довольно просто использовать std::reference_wrapper, чтобы избежать создания глубокой копии, и сделать практически то же самое, что вы хотели сделать изначально:

#include 
#include 
#include 

int myFunc(std::vector& vec1, std::vector& vec2) {
    for (auto const& vec : {std::ref(vec1), std::ref(vec2)}) {
        auto const &real_vec=vec.get();

        for (auto const& elem : real_vec) {
        }
    }
    return 0;
}

int main()
{
    std::vector vec1, vec2;

    myFunc(vec1, vec2);
    return 0;
}

Не глубокие копии.

Есть несколько различных решений:

  1. Итерация над std::initializer_list указателей, или std::reference_wrappers.

  2. Напишите лямбду, содержащую либо тело цикла, либо весь цикл. Вызовите ее дважды вручную.

  3. Напишите foreach_arg(lambda, args...).

  4. Напишите одновекторную версию как независимую функцию. Вызовите ее дважды.

  5. Напишите вариативную версию. Поместите цикл в лямбду и выполните его через запятую.

  6. Напишите вариативную версию как независимую функцию.

  7. Верните каждый вектор в std::span, затем сделайте std::initializer_list из двух span'ов и отправляйтесь в город.

  8. Напишите класс ref-array, оберните в него два вектора и отправляйтесь в город.

  9. Используем range-v3 для ленивой конкатенации векторов и выполняем итерации над конкатенацией.

Одним из решений может быть написание небольшой лямбды, которая "делает что-то", и тогда вам не придется повторять этот код несколько раз:

int myFunc(vector& vec1, vector& vec2) 
{
   auto do_something = [&](auto const & elem) {
        // do something
   }
 
   for (auto const& elem : vec1) {
        do_something(elem);
   }

   for (auto const& elem : vec2) {
        do_something(elem);    
   }
}

Если вы можете использовать библиотеку range-v3, вы можете написать это следующим образом:

int myFunc(vector& vec1, vector& vec2) 
{
   for (auto const& elem : ranges::views::concat(vec1, vec2)) {
        // dosomething    
   }
}

2022 WebDevInsider