代码之家  ›  专栏  ›  技术社区  ›  Fawar

std::vector<MyObj*>到std::vector<MyObj Const*>,如何没有循环?

  •  3
  • Fawar  · 技术社区  · 8 年前

    标题

    假设我们有

    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)
    }
    

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

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

    2 回复  |  直到 8 年前
        1
  •  1
  •   Nicol Bolas    8 年前

    好吧,总有人,总有一个地方需要循环。您可以通过使用 vector::assign :

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

    但是 assign 仍将循环。

    首选的现代解决方案是传递常量迭代器/指针对并让用户使用它们,或者使用类似的视图类 gsl::span . 这不需要复制任何内容,并且可以添加 const 根据需要:

    gsl::span<MyObj const*> spn(ArrayOfPtr.data(), ArrayOfPtr.size());
    
        2
  •  0
  •   Yakk - Adam Nevraumont    8 年前

    vector2 是一种根本不同的类型。但是,如果您只想查看 vector1 在一个 const 方式,我有一个解决方案给你。

    我会从这样的事情开始,但不完全是, 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 是正确的答案。

    Live example 通过一些测试。

    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)
    }
    

    作用 无法修改向量的长度或其中的指针或指针指向的对象。