Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle const/non const combination of getters without duplicate code? [duplicate]

Suppose I have a struct that has a name and some value associated with it:

struct Season {
  std::string name;
  // Mean temperature over the season
  double meanTemperature;
  // Days since the start of year when it's strongest
  float strongestAt;
  // Fraction of a year it applies to, compared to other seasons
  float yearFraction;
}

This class describes a season per year. Suppose I have a collection of them, which fills in the entire year:

// made up method that is supposed to find a season (I don't use it in real code)
int findIndex(const std::vector<Season>& in, std::function<bool(const Season&)>);
class SeasonCollection
{
public:
  const Season* GetSeason(const std::string& name) const
  {
    const int index = findIndex(_seasons, [name](const Season& s) { return s.seasonName == name; });
    return index != -1 ? &_seasons[index] : nullptr;
  }
  Season* GetSeason(const std::string& name)
  {
    const int index = findIndex(_seasons, [name](const Season& s) { return s.seasonName == name; });
    return index != -1 ? &_seasons[index] : nullptr;
  }
private:
  //! Settings for seasons
  std::vector<Season> _seasons;
};

In that collection you can see that I need to get both const Season* and Season*. That's because in some contexts, the collection is meant to be read-only and in some others, it is writeable.

There will also be other ways of getting a season, such as day of the year (eg. Christmas day 24.12). I want to have a const getter for each method of getting them, but I also do not want to copy-paste each of them and just add const.

What's the best approach?

like image 467
Tomáš Zato - Reinstate Monica Avatar asked Dec 13 '22 09:12

Tomáš Zato - Reinstate Monica


2 Answers

I hate to say it, but const_cast. What you do is make and call the const getter, and just remove the const that it returns since you know you are in a non-const object inside the non const getter. That would look like

  const Season* GetSeason(const std::string& name) const
  {
    const int index = findIndex(_seasons, [name](const Season& s) { return s.seasonName == name; });
    return index != -1 ? &_seasons[index] : nullptr;
  }
  Season* GetSeason(const std::string& name)
  {
    return const_cast<Season*>(const_cast<SeasonCollection const *>(this)->GetSeason(name));
    //     ^ remove the const^ ^ add const to call the const getter     ^^call const getter^
  }
like image 75
NathanOliver Avatar answered Mar 16 '23 00:03

NathanOliver


From Scott Meyers book, Effective C++, item 4:

When const and non-const member functions have essentially identical implementations, code duplication can be avoided by having the non-const version call the const version.

like image 20
Gupta Avatar answered Mar 16 '23 01:03

Gupta