std::vector< MyObj* > to std::vector< MyObj Const * >,如何无循环?

std::vector< MyObj* > to std::vector< MyObj Const * >, how to no loops?

本文关键字:std gt MyObj lt vector 循环 何无 to Const      更新时间:2023-10-16

Title,

假设我们有

std::vector<MyObj*> ArrayOfPtr;
std::vector<MyObj const *> ArrayOfPtrToConstObj;
int main()
{
     //I'd like to give ArrayOfPtr to another obj/function but not give it the right to modify the objects in it.
    ArrayOfPtrToConstObj = ArrayOfPtr;
    Function(ArrayOfPtrToConstObj)
}

为什么不能用C++编写并由编译器自动理解,考虑到 const 不会改变逻辑(优化或任何东西(..?

有没有一种快速的方法可以从向量 1 转到向量 2,而不必 for/while 循环到数组上并填充第二个?

好吧,某人,某个地方将不得不循环。您可以使用vector::assign避免自己编写循环:

ArrayOfPtrToConstObj.assign(ArrayOfPtr.begin(), ArrayOfPtr.end());

assign仍然会循环往复。

首选的现代解决方案是传递一个 const-iterator/pointer 对并让用户使用它们,或者使用像 gsl::span 这样的视图类。这不需要复制任何内容,并且可以根据需要添加const

gsl::span<MyObj const*> spn(ArrayOfPtr.data(), ArrayOfPtr.size());

vector2是一种根本不同的类型。 但是,如果您只想以const的方式查看vector1的内部,我为您提供了解决方案。

我会从类似但不完全是gsl::span的东西开始。

template<class T>
struct span {
private:
  T* b = 0;
  T* e = 0;
public:
  T* begin() const { return b; }
  T* end() const { return e; }
  T* data() const { return begin(); }
  template<class U>
  using compatible = std::enable_if_t< std::is_convertible< U*, T* >{} && sizeof(T)==sizeof(U), bool >;
  template<class U,
    compatible<U> =true
  >
  span( U* s, U* f ): b(s), e(f) {}
  template<class U,
    std::enable_if_t< std::is_convertible< U*, T* >{} && sizeof(T)==sizeof(U), bool > =true
  >
  span( U* s, std::size_t length ): span( s, s+length ) {}
  // pointer semantics:
  span()=default;
  span(span const&)=default;
  span& operator=(span const&)=default;
  ~span()=default;         
  std::size_t size() const{ return end()-begin(); }
  bool empty() const{ return end()==begin(); }
  T& front() const { return *begin(); }
  T& back() const { return *(end()-1); }
  // sub spans:
  span without_front( std::size_t n=1 ) const {
    n = (std::min)(n, size());
    return {begin()+n, end()};
  }
  span without_back( std::size_t n=1 ) const {
    n = (std::min)(n, size());
    return {begin(), end()-n};
  }
  span only_front( std::size_t n=1 ) const {
    n = (std::min)(n, size());
    return {begin(), begin()+n};
  }
  span only_back( std::size_t n=1 ) const {
    n = (std::min)(n, size());
    return {end()-n, end()};
  }
  span sub( std::size_t start, std::size_t length ) const {
    return without_front(start).only_front(length);
  }
  T& operator[](std::size_t I)const{ return begin()[I]; }
  T& at(std::size_t I)const{
     if (I>=size()) throw std::out_of_range{"index"};
     return begin()[I];
  }
  std::vector<std::decay_t<T>> as_vector()const& {
    return {begin(), end()};
  }
  std::vector<std::decay_t<T>> as_vector()&& {
    return {std::make_move_iterator(begin()), std::make_move_iterator(end())};
  }
  template<class C,
    compatible< std::decay_t< decltype( *std::declval<C&>().data() ) > > =true,
    std::enable_if_t< !std::is_same<span, std::decay_t<C>>{}, bool > =true
  >
  span( C&& c ): span(c.data(), c.size()) {}
};

如果您不打算更改上下文中vector的长度,则span是正确的答案。

带有一些测试的现场示例。

在这种情况下,Function应该采取span< MyObj const*const >,说明它只想查看MyObj const s的缓冲区。 如果需要,可以存储此类型的跨度,或者让隐式转换工作:

std::vector<MyObj*> ArrayOfPtr;
span<MyObj const*const> SpanOfPtrToConstObj;
int main()
{
  //I'd like to give ArrayOfPtr to another obj/function but not give it the right to modify the objects in it.
  SpanOfPtrToConstObj = ArrayOfPtr;
  Function(SpanOfPtrToConstObj)
}

Function无法修改矢量的长度或其中的指针或指针指向的内容。