是否可以在 C++11 中使用"array slicing"转换

Is it Possible to Use Casting as "array slicing" in C++11

本文关键字:array slicing 转换 C++11 是否      更新时间:2023-10-16

我有一些由专用硬件填充的共享内存。它被声明为一个结构体数组,如:

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的范围for循环来迭代数据。

然而:数组的最后一个维度(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-isms之外,这个比以前的要好。

for (auto & d : reinterpret_cast<int (&)[4]>(p))