How can I make a wrapper class for existing object, which automatically prohibits or allows modification of wrapped object's data depending if wrapped object was provided to constructor with or without const type qualifier.
So if wrapper class received (WrappedObj *ptr), then it allows set and get methods. If wrapper class received (const WrappedObj *ptr), then only get methods are allowed at compile time.
Problem example:
I have a pointer to buffer where there is Ethernet header and I want to ease access to Ethernet data for readability and reduce mistakes by endianess.
struct ethhdr {
uint8_t h_dst[6]; /* destination eth addr */
uint8_t h_src[6]; /* source ether addr */
uint16_t h_proto; /* packet type ID field */
uint8_t h_data[0];
} __attribute__((packed));
// My wrapper "view" class, which doesn't really work as expected
class EtherView {
public:
EtherView(uint8_t *ptr) : mPtr{(ethhdr*)ptr} {}
EtherView(const uint8_t *ptr) : mPtr{(ethhdr*)ptr} {}
/* SET METHODS */
void setProtocol(uint16_t proto) {
mPtr->h_proto = htons(proto);
}
/* ........ */
/* CONST GET METHODS */
uint16_t protocol() const {
return ntohs(mPtr->h_proto);
}
/* ........ */
private:
ethhdr *mPtr;
};
int main() {
uint8_t fakeBuffer[128];
EtherView ethView(fakeBuffer);
//OK - we want to modify because fakeBuffer isn't const
ethView.setProtocol(80);
const uint8_t *fakeConstBuff = fakeBuffer;
EtherView constEthView(fakeConstBuff);
// HERE I WANT COMPILE ERROR, because Wrapper was created with const param
constEthView.setProtocol(80);
/* I know its possible to define const wrapper:
const EtherView constEthView(fakeConstBuff);
, but I do not trust to "remember" to do it - it must be automatic. */
return 0;
}
As you can see this wrapper gives safe and importantly fast wrapper for buffer modification/reading. I've tested and it has the same performance as if buffer value modifications were done inline (because they are inlined by compiler).
Possible (not perfect) solutions so far:
1) Remember to add const for wrapper class, when const data source.
- Don't want to "remember" (will eventually make a mistake)
2) Make base class (EthViewConst) with getters and construct only on const source. Then inherit that class, which constructs on non-const source and has also setter functions. If there won't be any other solutions, then this probably will be the "best" way to do this, but:
- Doesn't really meet requirements. I would like to have one class, but if not possible, then its acceptable.
3) Have some special Factory, which creates const or non-const object depending on data source. "Pseudo code" example: [EtherView view = EtherView::Create(buffer);], but I can't seem to find a way to do it, because:
- returning const or non-const dynamically created Wrapper class pointer would work, but doesn't follow requirements: It must be fast. In this case it would be ralitively big cost.
- returning const/non-const object doesn't work, because "receiver" can define non-const object and constantness will be lost by copy construction
- returning reference can't be done for non-const object (becuase of temporary). Maybe there is some hacky way?
4) ..... any other solutions.....??
- move construction?
- perfect forwarding?
- templates?
- constexpr?
- preprocessor - no thanks