2015-05-06 14 views
7

Mam bazę danych C reprezentującą wektor wartości logicznych; z przyczyn poza moją kontrolą, boole "są przechowywane wewnętrznie jako liczby całkowite z dwiema magicznymi wartościami (nie 0 i 1 ...) reprezentującymi true i false. Stworzyłem klasę C++ owijającą tę strukturę C i działa ona ładnie. I wdrożyły set() i get() metod jak:Przeciążenie C++ [] z transformacją

void Class::set(size_t index , bool value) { 
    if (value) 
     c_ptr[index] = SPECIAL_TRUE_VALUE; 
    else 
     c_ptr[index] = SPECIAL_FALSE_VALUE; 
} 

Działa to ok; ale najlepiej chciałbym przeciążać operatora [], jednak nie jest dla mnie jasne, jak/jeśli mogę to zrobić - ze względu na specjalną transformację między wartościami bool a wartościami całkowitymi?

+1

Musisz przeczytać trochę o * klasach proxy * – vsoftco

+0

Tak - nauczyłem się dzisiaj o klasach proxy i przeciążaniu operatora przypisania; na co generalnie niechętnie. – user422005

+0

To może, ale nie musi być opłacalne dla twojego rozwiązania, ale powinieneś pomyśleć o częstotliwości transformacji a częstotliwości dostępu boolowskiego. Jeśli używasz przede wszystkim funkcji set/get/[] i rzadko korzystasz z transformacji SPECIAL _ * _ VALUE, łatwiejsze może być przechowywanie boolów, a następnie transformowanie tylko w razie potrzeby. – nic

Odpowiedz

7
struct pseudo_reference { 
    operator bool()const&&{ 
    return c->get(index); 
    } 
    pseudo_reference operator=(bool b)&&{ 
    c->set(index, b); 
    return {c,index}; 
    } 

    // sometimes having named functions is useful: 
    bool get() const&& { 
    return std::move(*this); 
    } 
    void set(bool b)&& { 
    std::move(*this) = b; 
    } 
    pseudo_reference()=delete; 
private: 
    Class* c; 
    size_t index; 
    pseudo_reference(pseudo_reference&&o)=default; // not exposed 
    pseudo_reference(Class* pc, size_t i):c(pc),index(i){} 
    friend class Class; 
}; 

W Class:

pseudo_reference operator[](size_t i){ 
    return {this, i}; 
} 
bool operator[](size_t i)const{ 
    return c_ptr[index] == SPECIAL_TRUE_VALUE; 
} 

ja przechowywane zarówno wskaźnik i indeksu, więc unikam reimplementing logikę get/set w moim pseudo_reference. Takie pseudo_references prawdopodobnie będą krótkotrwałe, więc optymalizacja rozmiaru prawdopodobnie nie jest ważna.

Zablokowałem wszystkie operacje poza rwartością, aby zniechęcić do przechowywania pseudo_reference. Możesz uczynić wymienione operacje niezwiązanymi z wartościami rrawnymi względnie nieszkodliwymi, ale z mojego doświadczenia wynika, że ​​wartości pseudo_references zachowują się jak referencje, więc lepiej, jeśli nie utrzymują się.

Ktoś może nadal przechowywać pseudo_reference przez auto&& x = c[33];, ale korzystanie z niego bez tej funkcji nie będzie możliwe. Miejmy nadzieję, że złapie to za bardzo podatne na błędy. auto x = c[33]; nie będzie działać.

+0

W odpowiedzi na próbę edycji przez @ user1978011: celowo zrobiłem to prywatne. 'Klasa klasy przyjaciela' powinna pozwolić' klasie' na skonstruowanie 'pseudo_reference's. – Yakk

+0

OK - myślę, że rozumiem, jak to działa? Będziesz tworzyć instancję pseudo_referencji dla każdego dostępu do metody 'set()'? To wydaje się trochę ciężkie? – user422005

+1

@ user422005 jest wskaźnikiem (do 'Class') i' size_t'. Jaka jest ta waga? Odwołanie jest zwykle zaimplementowane (jeśli nie jest podkreślane), więc mówimy tylko o kilka bajtów, które zwracają odwołanie do danych. Kompilator warty swojej soli może wbudować go w życie, ponieważ żyje tylko na tyle długo, aby w ogóle zadzwonić do 'set' lub' get' na wskaźniku. Wykonuj profilowanie z optymalizacją względem surowego wywołania 'get' lub' set' i byłbym zszokowany, gdyby była duża różnica. małe obiekty na stos, które od razu odejdą, są ** tanie **. – Yakk

1

Możesz zwrócić wrapper klasy helper, która obsługuje dla ciebie zadanie.

struct WrapMe { 
    c_ptr_T &value; 
    WrapMe(c_ptr_T &_value) : value(_value) {} 
    // handles assignment of bool values 
    WrapMe & operator=(const bool b) { 
     value = (b) ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE; 
     return *this; 
    } 
    // handles cast to bool 
    operator bool() const { return value == SPECIAL_TRUE_VALUE; } 
}; 

class Class { 
    WrapMe operator[](const int idx) { return WrapMe(c_ptr[idx]); } 
    // ... 
}; 
2

celu realizacji operator[](), trzeba zwrócić obiekt proxy, który ma rzeczywistej zadanie, gdy pojawia się na lewej stronie =-:

struct proxy { 
    proxy& operator=(bool value) { 
     c_.c_ptr[ index_ ] = value ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE; 
     return *this; 
    } 
    operator bool() const { // for when it's just used normally, not = 
     return c_ptr[ index ] == SPECIAL_TRUE_VALUE; 
    } 
private: 
    Class &c_; 
    size_t const index_; 
    proxy(Class &c, size_t index) : c_(c), index_(index) { } 
    friend class Class; 
} 

class Class { 
public: 
    proxy operator[](size_t index) { 
     return proxy(*this, index); 
    } 
    bool operator[](size_t index) const { // read-only access is easy 
     return c_ptr[ index ] == SPECIAL_TRUE_VALUE; 
    } 
    // ... 
}; 

Albo coś w tym stylu.

Powiązane problemy