开发者

Vector, proxy class and dot operator in C++

开发者 https://www.devze.com 2023-03-30 19:00 出处:网络
A question related to a custom Vector class in C++. template <typename T> class Vector { ... private:

A question related to a custom Vector class in C++.

template <typename T>
class Vector
{ ...
  private:
    T * mData; int mSize;
  public:
    proxy_element operator[](const size_type index) { return proxy_element(*this, index); }
    const T& operator[](const size_type index) const {   return mData[index]; }
};

template <typename T>
class proxy_element
{  ...
   proxy_element(Vector<T>& m_parent, const size_type index);
   proxy_elem& operator=(const T& rhs); // modifies data so invalidate on other memories
   bool operator==(const proxy_elem& rhs) // only read, just copy data back.
   ...
}

The reason for using proxy_element class is to distinguish and optimize read and writes operations, considering that the vector data can reside in GPU device memories as well. So any read operation require only to copy latest data back (if any) but a readwrite/write operation require invalidating data in device memories.

This design work well when the element type is primitive. However for more complex element types, there is one issue:

struct person{ int age; double salary; }; 
int main()
{
   Vector<person> v1(10); 
   v[1].age = 10; // gives error as operator[] returns proxy_element for which "." operator has no meaning
}

AFAIK, the "." operator cannot be overload in C++. One obvious solution is to not use proxy_elem and just return regular reference (T &), assuming that each access is a write access, but that will be inefficient for obvious reasons.

Is there any other work around which gives me "." operator working while retaining ability to distinguish between read开发者_如何学Go and write operations?


One option is to make such data types immutable (private member variables, initialised by a constructor, and the only setter is the class's assignment operator). This way, the only means to change anything is to assign to an entire instance of the class, which can be channeled through a proxy_element.


Marcelo Cantos's answer is, of course, the proper way to do things. However, there is the complicated and crazy workaround of specialization. (Not recommended.)

//if it's a class, inherit from it to get public members
template<class T> 
class proxy_element : public T {
    ...
    proxy_element(Vector<T>& m_parent, const size_type index);
    proxy_elem& operator=(const T& rhs); // modifies data so invalidate on other memories
    bool operator==(const proxy_elem& rhs) // only read, just copy data back.
    ...
};
//pretend to be a pointer
template<> 
class proxy_element<T*> {
    ...
    proxy_element(Vector<T>& m_parent, const size_type index);
    proxy_elem& operator=(const T& rhs); // modifies data so invalidate on other memories
    bool operator==(const proxy_elem& rhs) // only read, just copy data back.
    ...
};
//otherwise, pretend to be primitive
#define primitive_proxy(T) \
template<> class proxy_element {
    ...
    proxy_element(Vector<T>& m_parent, const size_type index);
    proxy_elem& operator=(const T& rhs); // modifies data so invalidate on other memories
    bool operator==(const proxy_elem& rhs) // only read, just copy data back.
    ...
};
primitive_proxy(char)
primitive_proxy(unsigned char)
primitive_proxy(signed char) //this is distinct from char remember
primitive_proxy(short)
primitive_proxy(unsigned short)
primitive_proxy(int)
primitive_proxy(unsigned int)
primitive_proxy(long)
primitive_proxy(unsigned long)
primitive_proxy(long long)
primitive_proxy(unsigned long long)
primitive_proxy(char16_t) //if GCC
primitive_proxy(char32_t) //if GCC
primitive_proxy(wchar_t)
primitive_proxy(float)
primitive_proxy(double)
primitive_proxy(long double)
0

精彩评论

暂无评论...
验证码 换一张
取 消