Imagine I have a class Sender that:
- takes in a message
- makes some checks to decide whether the message should be sent out or discarded
- translates the message, using a
Translatorinterface - sends out the message
Note that translating is expensive and should be avoided if the message is discarded, so translation cannot be done eagerly before passing the message to the Sender.
I've designed my code like this:
class Translator {
public:
virtual Message translate(Message inputMessage) = 0;
};
class Sender {
public:
void send(Message message, Translator& translator) const;
}
Note that translate is not const, and translator is not passed by const ref to Sender. Sender doesn't care whether translate is const or not, it's not its problem. To be as generic as possible, Sender does not require translate to be const, as this would overly restrict implementations of Translator.
Now say that I want to use the Sender as follows:
class MessageGenerator {
private:
class NoopTranslator : public Translator {
public:
Message translate(Message inputMessage) override {
return std::move(inputMessage);
}
}
NoopTranslator translator_;
Sender sender_;
public:
void createMessageAndSend() const {
Message newMessage{};
sender_.send(std::move(newMessage), translator_);
}
};
This code does not compile, because createMessageAndSend is declared const, so translator_ cannot be passed as non-const reference to Sender. I don't want to compromise on createMessageAndSend() to be const. After all, there is definitely no state mutation.
I believe in this case, it is fair to do the following:
void createMessageAndSend() const {
Message newMessage{};
sender_.send(std::move(newMessage), const_cast<Translator&>(translator_));
}
Because I can confirm that NoopTranslator doesn't actually mutate state.
What do you think? Is there a fundamental flaw in my design, which forces me to use const_cast when a different approach would allow me to avoid it?
Rather than
const_casthere, I would marktranslator_mutable. This assumes that there are someTranslators which are mutated when translating, otherwise it would be better to takeconst Translator &inSender::send.