У меня есть общая память, заполненная специализированным оборудованием. Он объявлен как массив структур, например:
struct port {
int data[10];
char port_id[8];
}
struct bus {
port ports[5];
char bus_id[8];
}
struct bus busses[10];
Я (пере) изучаю C ++ и хотел использовать циклы C ++ 11 для циклического перебора данных.
ОДНАКО: Это последнее измерение массива (data[10]
), Я забочусь только о первых 4 элементах. Есть ли способ взять кусок данных и использовать его в операторе for ()?
подобно
for (auto & b : busses) {
for (auto & p : bus.ports) {
for (auto & d : port.data[0 through 3]) {
store_the_address_of_d_for_use_elsewhere(d);
}
}
}
Есть ли способ использовать приведение во внутреннем цикле for, чтобы казалось, что есть только 4 элемента? Адрес данных важен, потому что я собираюсь обратиться к нему позже, используя указатели.
Это, наверное, один из тех времен, когда старый добрый старомодный for (int i = 0; i < 4; i++)
это ваша лучшая ставка.
Не задумывайтесь над этим и не пытайтесь использовать «новые» функции только ради этого, создавая больше сложности и больше работы в процессе.
template<class T>
struct array_view {
T* b = 0;
T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
std::size_t size() const { return end()-begin(); }
T& front() const { return *begin(); }
T& back() const { return *(end()-1); }
// basic constructors:
array_view(T* s, T* f):b(s), e(f) {}
array_view(T* s, std::size_t N):array_view(s, s+N) {}
// default ctors: (no need for move)
array_view()=default;
array_view(array_view const&)=default;
array_view& operator=(array_view const&)=default;
// advanced constructors:
template<class U>
using is_compatible = std::integral_constant<bool,
std::is_same<U, T*>{} || std::is_same<U, T const*>{} ||
std::is_same<U, T volatile*>{} || std::is_same<U, T volatile const*>{}
>;
// this one consumes containers with a compatible .data():
template<class C,
typename std::enable_if<is_compatible< decltype(std::declval<C&>().data()) >{}, int>::type = 0
>
array_view( C&& c ): array_view( c.data(), c.size() ) {}
// this one consumes compatible arrays:
template<class U, std::size_t N,
typename std::enable_if<is_compatible< U* >{}, int>::type = 0
>
array_view( U(&arr)[N] ):
array_view( arr, N )
{}
// create a modified view:
array_view without_front( std::size_t N = 1 ) const {
return {begin()+(std::min)(size(), N), end()};
}
array_view without_back( std::size_t N = 1 ) const {
return {begin(), end()-(std::min)(size(), N)};
}
array_view only_front( std::size_t N = 1 ) const {
return {begin(), begin()+(std::min)(size(), N)};
}
array_view only_back( std::size_t N = 1 ) const {
return {end()-(std::min)(size(), N), end()};
}
};
Теперь некоторые функции, которые позволяют легко создать его:
template<class T, std::size_t N>
array_view<T> array_view_of( T(&arr)[N] ) {
return arr;
}
template<class C,
class Data = decltype( std::declval<C&>().data() ),
class T = typename std::remove_pointer<Data>::type
>
array_view<T> array_view_of( C&& c ) {
return std::forward<C>(c);
}
template<class T>
array_view<T> array_view_of( T* s, std::size_t N ) {
return {s, N};
}
template<class T>
array_view<T> array_view_of( T* s, T* e ) {
return {s, e};
}
и мы сделали шаблонную часть.
for (auto & b : bus) {
for (auto & p : bus.port) {
for (auto & d : array_view_of(bus.data).only_front(4)) {
store_the_address_of_d_for_use_elsewhere(d);
}
}
}
Теперь я бы только защищал этот подход, потому что array_view
шокирующе полезен во многих различных приложениях. Написание этого только для этого случая глупо.
Обратите внимание, что выше array_view
является многократно повторяемым классом; Я написал это здесь раньше. Этот, на мой взгляд, лучше, чем предыдущие, кроме раздражающих C ++ 11-Измы мне пришлось использовать.
for (auto & d : reinterpret_cast<int (&)[4]>(p))