0

I'm writing a function that calculates various statistics of a numeric stream of values. It has various template parameters to conditionally calculate other, more expensive things like median and mode. They are templates so the compiler will optimize out all the if statements. Depending on the template values, the getters for the more expensive values are disabled if they were not calculated.

template <bool CalcMedian>
class Stats
{
public:
      // median getter, disabled if it wasn't calculated
      template <bool B = CalcMedian, typename = std::enable_if_t<B>>
      double median() const { return _median; }

      void add_element(double value) {
          // update easy values
          if (CalcMedian) {
              // update the median
          }
      }
};

Everything is well and dandy, except when I go to overload << for the class.

template <bool CalcMedian>
std::ostream& operator<<(std::ostream& o, const Stats<CalcMedian>& stats) {
    // display the easy stats
    if (CalcMedian) {
        o << "median = " << stats.median();
        // g++: no matching function call for Stats<false>::median()
    }
}

One solution is to specialize the class to remove the getters, or the operator<< so it doesn't use the if statement, but I plan to include at least 3 parameters, which is already 8 variations of the function I'd have to write. Adding any more template parameters would be a huge pain.

I have already tried the method illustrated in this answer, but it doesn't work. The test method gives a true_type because the method does actually exist, it is just disabled by enable_if so I get the same compiler error. Is there a way to modify that answer to capture the fact that the function exists, but is disabled?

Community
  • 1
  • 1
twentylemon
  • 1,248
  • 9
  • 11

1 Answers1

2

You may create a display_median specialized:

template <bool B = CalcMedian>
std::ostream&o display_median(std::ostream&o) const;

template <>
std::ostream&o display_median<true>(std::ostream&o) const;
{
    return o << "median = " << median() << std::endl;
}

template <>
std::ostream&o display_median<false>(std::ostream&o) const;
{
    return o;
}

then

template <bool CalcMedian>
std::ostream& operator<<(std::ostream& o, const Stats<CalcMedian>& stats) {
    // display the easy stats
    stats.display_median<CalcMedian>(o);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302