I have a C datastructure representing a vector of boolean values; for reasons outside of my control the bools' are stored internally as integers with two magical values (not 0 and 1 ...) representing true and false. I have created a C++ class wrapping this C structure, and it works nicely. I have implemented the set()
and get()
methods as:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
This works ok; but ideally I would like to overload operator[], however it is not clear to me how/if I can do that - due to special transformation between bool and the integer values?
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;
};
In Class
:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
I stored both a pointer and an index, so I avoid reimplementing the logic of get
/set
in my pseudo_reference
. Such pseudo_references
are likely to be short-lived, so size optimization probably isn't important.
I blocked all non-rvalue operations to discourage storing a pseudo_reference
. You can make said operations non-rvalue restricted relatively harmlessly, but in my experience pseudo_references
are values that behave like references, so it is better if they don't persist.
Someone can still store a pseudo_reference
via auto&& x = c[33];
, but using it without move
ing it won't be possible. Hopefully that catches most error-prone uses of it. auto x = c[33];
won't work.
To implement operator[]()
, you need to return a proxy object that does the actual assignment when it appears on the left-hand-side of =
:
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;
}
// ...
};
Or something like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With