Вектор, прокси-класс и оператор точки в C ++ - PullRequest
1 голос
/ 25 августа 2011

Вопрос, связанный с пользовательским классом Vector в 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.
   ...
}

Причина использования класса proxy_element состоит в том, чтобы различать и оптимизировать операции чтения и записи, учитывая, что векторные данные также могут находиться в памяти устройства GPU. Поэтому любая операция чтения требует только копирования последних данных обратно (если таковые имеются), но операция чтения / записи требует аннулирования данных в памяти устройства.

Этот дизайн хорошо работает, когда тип элемента примитивен. Однако для более сложных типов элементов есть одна проблема:

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, "." Оператор не может быть перегружен в C ++. Одно очевидное решение состоит в том, чтобы не использовать proxy_elem и просто возвращать обычную ссылку (T &), предполагая, что каждый доступ является доступом для записи, но это будет неэффективно по очевидным причинам.

Есть ли какая-то другая работа, которая дает мне "." оператор работает, сохраняя способность различать операции чтения и записи?

Ответы [ 2 ]

1 голос
/ 25 августа 2011

Один из вариантов - сделать такие типы данных неизменяемыми (закрытые переменные-члены, инициализируемые конструктором, и единственным установщиком является оператор присваивания класса). Таким образом, единственное средство что-либо изменить - назначить целому экземпляру класса, который можно направить через proxy_element.

0 голосов
/ 25 августа 2011

Ответ Марсело Кантоса - это, конечно, правильный способ сделать что-то. Тем не менее, есть сложный и сумасшедший обходной путь специализации. (Не рекомендуется.)

//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)
...