Pregunta

I'm trying to use a boost accumulator to calculate a rolling mean. When I declare the variable inline like this:

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>

using namespace boost::accumulators;

int main()
{
  // Define rolling_mean accumulator
  accumulator_set<double, stats<tag::rolling_mean > > acc(tag::rolling_window::window_size = 5);
    // push in some data ...
    acc(1.2);
    acc(2.3);
    acc(3.4);
    acc(4.5);

    // Display the results ...
    std::cout << "Mean:   " << rolling_mean(acc) << std::endl;

    return 0;
}

It works just fine. When I declare the accumulator as a member of a class like so:

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>

using namespace boost::accumulators;

class DoMean {
private:
  accumulator_set<double, stats<tag::rolling_mean > > m_acc(tag::rolling_window::window_size = 5);

public:

  void addData(double val) {
    this->m_acc(val);
  }

  double getMean(void) {
    return rolling_mean(this->m_acc);
  }
};

int main()
{
  // Define an accumulator set for calculating the mean and the
  // 2nd moment ...
  DoMean meaner;
  meaner.addData(1.2);
  meaner.addData(2.3);
  meaner.addData(3.4);
  meaner.addData(4.5);

  // push in some data ...

  // Display the results ...
  std::cout << "Mean:   " << meaner.getMean() << std::endl;

  return 0;
}

It fails, giving the compiler errors:

accumulators::tag::rolling_window::window_size is not a type
...blah blah, many type template errors etc.
¿Fue útil?

Solución

The correct solution to this problem is this:

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>

using namespace boost::accumulators;

class DoMean {
private:
  accumulator_set<double, stats<tag::rolling_mean > > m_acc;

public:

  DoMean(void): m_acc(tag::rolling_window::window_size = 5) {}

  void addData(double val) {
    this->m_acc(val);
  }

  double getMean(void) {
    return rolling_mean(this->m_acc);
  }
};

int main()
{
  // Define an accumulator set for calculating the mean and the
  // 2nd moment ...
  DoMean meaner;
  meaner.addData(1.2);
  meaner.addData(2.3);
  meaner.addData(3.4);
  meaner.addData(4.5);

  // push in some data ...

  // Display the results ...
  std::cout << "Mean:   " << meaner.getMean() << std::endl;

  return 0;
}

Notice that the initialization of m_acc has been moved from inline with it's declaration, into the initialization list. This solves all the compiler errors. In fact, if we think about what's happening here, the reason that the initial attempt at using the accumulator in a class fails is because ISO c++ forbids initialization of members inline.

We can demonstrate this with another simple class:

#include <iostream>

class TestInit {
public:
  int m_init = 10;

};

int main() {
  TestInit inits;
  std::cout << "The value: " << inits.m_init << std::endl;

}

Now the compiler gives us a helpful message:

/home/me/prog/cpp/acctest/testinit.cxx:5:16: error: ISO C++ forbids initialization of member m_init [-fpermissive]
/home/me/prog/cpp/acctest/testinit.cxx:5:16: error: making m_init static [-fpermissive]
/home/me/prog/cpp/acctest/testinit.cxx:5:16: error: ISO C++ forbids in-class initialization of non-const static member m_init
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top