Вектор передачи & lt; reference_wrapper & lt; int & gt; & GT; чтобы вектор & lt; int & gt ;?

У меня большой std::vector<int> a, но я хотел бы работать только над его подмножеством. Идея заключалась в том, чтобы создать std::vector<reference_wrapper<int> > refa который содержит только указанное подмножество (в mwe все элементы 1< a < 4). Я бы тогда хотел пройти refa к функциям, которые ожидают std::vector<int> или же std::vector<int>& в качестве аргументов (потому что я также хочу использовать их с a). a может быть довольно большим, и я хочу избежать выбора несколько раз.

Вопросы

Как правильно пройти refa к функциям? Что я хочу это bar(refa) а также foobar(refa) работать.

Есть ли лучший способ решить проблему, не меняя функций (слишком много)?

Код

#include <functional>
#include <iostream>
#include <vector>int foo(int &a)
{
a++;
return 0;
}

int bar(std::vector<int> &va)
{
for(auto &vaa : va)
vaa++;

return 0;
}

int foobar(std::vector<int> va)
{
for(auto &vaa : va)
vaa++;

return 0;
}int main()
{
std::vector<int> a= {1, 2, 3, 4, 5};
std::vector<std::reference_wrapper<int> > refa;

//Fill refa
for(auto &aa : a)
{
if(aa>1 && aa<4) refa.push_back(std::ref(aa));
}//works
// for(auto &aa : refa)
//   aa++;

//works
//  bar(a);

//works, a unchanged
//  foobar(a);

//works
// for(auto &aa : refa)
//   foo(aa);

//works
// for(int &aa : refa)
//  foo(aa)

// does not work
// conversion from vector<reference_wrapper<int> > to vector<int>& or vector<int> required
bar(refa);
//  foobar(refa);for(auto &aa : a)
std::cout << aa << std::endl;return 0;
}

Заметка
int используется только для упрощения примера.

2

Решение

Я бы определенно использовал итераторы особенно учитывая вашу проблему впереди (работа над подмножеством вектора):

template<class Iterator>
int bar(Iterator begin, Iterator end)
{
for (auto it = begin; it != end; ++it)
(*it)++;
return 0;
}

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

bar(a.begin() + 2, a.begin() + 4);

Например, с помощью приведенного выше кода вы будете посещать элементы с 1 по 4 (оба исключены). А также ВотЖивой пример.

5

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

Лучше всего сделать так, чтобы функции панели функций и шаблонов foobar были такими:

template <typename TContainer>
int bar(TContainer& va)
{
for(auto& vaa : va)
vaa++;

return 0;
}

Без переопределения вашей функции для принятия «типов, которые выглядят как векторные», я не думаю, что есть способ достичь того, чего вы хотите.

3

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

Контейнер является итеративным диапазоном, и владельцем его содержимого.

В случае vectorЭто непрерывный итерируемый диапазон и владелец содержимого. Скорее всего, вам нужно только знать, является ли итеративный диапазон произвольного доступа в вашем коде реализации.

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

Сама идея смежного диапазона мне нравится:

template<typename T>
struct contiguous_range {
T* b; T* e;
contiguous_range( contiguous_range const& ) = default;
contiguous_range():b(nullptr), e(nullptr) {};
contiguous_range& operator=( contiguous_range const& ) = default;
std::size_t size() const { return e-b; }
T* begin() const { return b; } // note, T*
T* end() const { return e; } // note, T*
template<typename U, typename=typename std::enable_if<
sizeof(U)==sizeof(T)
&& std::is_convertible<U*, T*>::value
>::type>
contiguous_range( contiguous_range<U> const& o ):b(o.b), e(o.e) {};
T& operator[]( std::size_t i ) const { return b[i]; }

template<typename A>
contiguous_range( std::vector<T, A> const& v ):b(v.data()), e(v.data()+v.size()) {}
template<typename U, std::size_t N, typename=typename std::enable_if<
sizeof(U)==sizeof(T)
&& std::is_convertible<U*, T*>::value
>::type>
contiguous_range( std::array<U, N> const& a ):b(a.data()), e(a.data()+a.size()) {}
template<typename U, std::size_t N, typename=typename std::enable_if<
sizeof(U)==sizeof(T)
&& std::is_convertible<U*, T*>::value
>::type>
contiguous_range( U(&a)[N] ):b(&a[0]), e((&a[0])+N) {}

template<typename U, typename=typename std::enable_if<
sizeof(U)==sizeof(T)
&& std::is_convertible<U*, T*>::value
>::type>
contiguous_range( U* b_, U* e_ ):b(b_), e(e_) {}
};

template<typename I>
auto contiguous_subrange( I b, I e )
-> contiguous_range<std::iterator_traits<I>::value_type>
{
return {&*b, &*e};
}
template<typename C>
auto contiguous_subrange( C&& c, std::size_t start, std::size_t end )
-> decltype( contiguous_subrange( &c[start], &c[end] ) )
{ return ( contiguous_subrange( &c[start], &c[end] ) ) };

Теперь наши функции могут просто взять contiguous_range<int> или же continguos_range<const int>и они могут быть неявно переданы std::vector<int>,

Вы также можете настроить поддиапазоны вашего std::vector которые одинаково смежны.

Обратите внимание, что constiguous_range<int> соответствует std::vector<int>&и contiguous_range<const int> соответствует std::vector<int> const&,

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