c++c++11constantscode-reusefunction-qualifier

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


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?


Solution

  • 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^
      }