struct BananaHolder
{
vector<Banana>& getBananas();
const vector<Banana>& getBananas() const;
};
My classes are cluttered with this kind of duplication.
Is there a cleaner, more elegant alternative?
struct BananaHolder
{
vector<Banana>& getBananas();
const vector<Banana>& getBananas() const;
};
My classes are cluttered with this kind of duplication.
Is there a cleaner, more elegant alternative?
If your class has to return references, and if it has to return a reference to a modifiable vector when invoked on a modifiable object, then I do not think there is a way to avoid the duplication - at least, not the duplicate declaration.
Notice, that some types of the Standard Library also suffer from the same problem. For instance, sequence containers such as std::vector have both a const and a non-const overload of operator [], at(), back(), front(), data(), and so on.
In C++23, you can solve this issue with explicit object parameters (aka deducing this):
struct BananaHolder
{
vector<Banana> m_bananas;
// using abbreviated function templates
auto& getBananas(this auto&& self) {
return self.m_bananas;
}
// or more verbosely
template <typename Self>
auto& getBananas(this Self&& self) {
return self.m_bananas;
}
};
This not only covers const BananaHolder and BananaHolder, it covers all combinations of const, volatile, lvalue reference, and rvalue reference qualifications.
If you wanted to make full use of this, you would write:
// to get the same behavior without templates, we would need 16 overloads
template <typename Self>
auto&& getBananas(this Self&& self) {
// without std::forward, this would always return an lvalue reference
return std::forward<Self>(self).m_bananas;
}
Prior to C++23, there is no way to avoid having at least two member functions. You would have to write two getter overloads like you did, for example.
For something more complicated than a getter, see How do I remove code duplication between similar const and non-const member functions?.