簡體   English   中英

使更長的std :: array變得更短

[英]Make longer std::array accessible as if it's shorter

我正在實現我的靜態多維向量類。 我使用std::array作為基礎數據類型。

template <typename T, std::size_t N>
class Vector {
    private:
    std::array<T, N> data;
};

我想讓我的課向下兼容,所以我在寫:

template <typename T, std::size_t N>
class Vector : public Vector<T, N-1>{
    private:
    std::array<T, N> data;
};

template <typename T>
class Vector<T, 0> {};

我的目標是,當在向下兼容模式下使用一個實例時,應該能夠可靠地訪問其基礎數據:

template<typename T, std::size_t N>
T& Vector<T, N>::operator[](int i) {
    // Do boundary checking here
    return this->data[i];
}

void foo(Vector<int, 3>& arg) {
    arg[1] = 10;
}

Vector<int, 5> b;
foo(b);
// Now b[1] should be 10

這里有兩點:

  • Vector<T, 5>應該被foo()接受, Vector<T, 2>應該被拒絕。
  • foo()b[0]b[2]更改應該適用。 b[3]b[4]不應在foo()訪問。

我該如何實現?

圍繞std::array<>本身的簡單讀取包裝怎么樣?

template<typename T, std::size_t N>
struct ArrayReader {
public:
  // Intentionally implicit.
  template<std::size_t SRC_LEN>
  ArrayReader(std::array<T, SRC_LEN> const& src) 
  : data_(src.data()) {
    static_assert(SRC_LEN >= N);
  }
private:
  T const* data_;
};

void foo(ArrayReader<float, 3>);
void bar() {
    std::array<float, 4> a;
    std::array<float, 2> b;

    foo(a);
    foo(b); //BOOM!
}

當然,您可以輕松地將std::array替換為您自己的類型,這只是原理的一個示例。

array保留數據,然后創建其他非所有者類,例如array_view僅保留指針。 它具有接受數組的通用構造函數,並且具有static_assert來檢查大小。

這是我的處理方法:

template <class Container, std::size_t size>
struct range_view
{
  range_view(Container * p): container(p) { assert(size <= p->size()); }
  auto & operator[](std::size_t i) { return (*container)[i]; }
 private:
  Container * container;
};

然后,您只需將foo定義為:

template <class C>
void foo(range_view<C, 3> c)
{
  c[1] = 1;
}

這是最接近我認為您需要的東西。

使Vector成為數據的查看者/用戶,而不是數據的所有者。

#include <array>

template <typename T, std::size_t N, std::size_t I>
class Vector : public Vector<T, N, I-1>
{
   public:
      Vector(std::array<T, N>& arr) : Vector<T, N, I-1>(arr), arr_(arr) {}

      T& operator[](int i) {
         return arr_[i];
      }

   private:
      std::array<T, N>& arr_;
};

template <typename T, std::size_t N>
class Vector<T, N, 0ul>
{
   public:
      Vector(std::array<T, N>& arr) : arr_(arr) {}
   private:
      std::array<T, N>& arr_;
};

void foo(Vector<int, 5, 3>& arg) {
    arg[1] = 10;

    // Can't find a way to make this a compile time error.
    arg[3] = 10;
}

#include <iostream>

int main()
{
   std::array<int, 5> arr;
   Vector<int, 5, 5> b(arr);
   foo(b);
   std::cout << b[1] << std::endl;
}

這是如何實現您在問題中嘗試過的Vector類的演示。 在每個級別上,您只存儲1個值而不是一個數組,這樣,當您將所有N Array組合在一起時,您將獲得N值的空間。 當然,然后調用operator[]很棘手,這就是我要演示的內容。

#include <utility>

template <class T, std::size_t N>
struct Array : Array<T, N-1>
{
    T & operator[](std::size_t i)
    {
        return const_cast<T&>((*const_cast<const Array*>(this))[i]);
    }

    const T & operator[](std::size_t i) const
    {
        return Get(i, std::make_index_sequence<N>());
    }

    template <std::size_t i>
    const T & Geti() const
    {
        return static_cast<const Array<T, i+1>&>(*this).GetValue();
    }

    const T & GetValue() const { return value; }

    template <std::size_t ... indices>
    const T & Get(std::size_t i, std::integer_sequence<std::size_t, indices...>) const
    {
        using X = decltype(&Array::Geti<0>);
        X getters[] = { &Array::Geti<indices>... };
        return (this->*getters[i])();
    }

    template <std::size_t i, class = typename std::enable_if<(i <= N)>::type>
    operator Array<T, i>&() { return (Array<T, i>&)*this; }
private:
    T value;
};

template <class T>
struct Array<T, 0>{};

void foo(Array<float, 3> & a) { a[1] = 10; }

int main()
{
    Array<float, 10> a;
    foo(a);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM