Struggling with first use of templates

I've done a bunch of research on class templates, and looked at examples, but I'm having trouble implementing.

I have a RollingAverage class that was written to handle an array of int, but I want it to be able to use other data types.

Here's my code:

Header file:

template <typename T> class RollingAverage {
  private:
    T* ptr;

    static const int maxNumSamples = 100;

    T sampleArray[maxNumSamples];
    int numSamples = maxNumSamples;
    int numSamplesTaken = 0;
    int sampleIndex = 0;
    T previousRollingAverage = 0;
    T rollingAverage;
    unsigned long sampleSum = 0;

  public:
    RollingAverage(int numSamples);
    //RollingAverage(); 
    void reset();
    void clear();
    void initialize(int numSamples);
    T takeSample(T sample);
    T getLastNthSample(T n);
    int getSlope();
    int getAverage();

    T getSampleSum();
    int getNumSamplesTaken();
    int getMaxNumSamples();

};

CPP file

template <typename T> RollingAverage<T>::RollingAverage(int numSamples){
  initialize(numSamples);
}

template <typename T> void RollingAverage<T>::reset(){
  clear();
  numSamples = maxNumSamples;
}

template <typename T> void RollingAverage<T>::clear(){
  numSamplesTaken = sampleIndex = rollingAverage = previousRollingAverage = sampleSum = 0;
}

template <typename T> void RollingAverage<T>::initialize(int numSamples){
  if(numSamples<=maxNumSamples){this->numSamples=numSamples;}
  numSamplesTaken = 0;
  sampleIndex = 0;
  previousRollingAverage = 0;
  rollingAverage;
  sampleSum = 0;
}

template <typename T> T RollingAverage<T>::takeSample(T sample){
  if(numSamplesTaken < numSamples){ numSamplesTaken++; }
  if(++sampleIndex == numSamples){ sampleIndex = 0; }

  sampleSum += sample;
  sampleSum -= sampleArray[sampleIndex];   
  sampleArray[sampleIndex] = sample;

  previousRollingAverage = rollingAverage;
  rollingAverage = (int) (sampleSum / (long) numSamplesTaken);
  return rollingAverage;
}

template <typename T> T RollingAverage<T>::getSampleSum(){
  return sampleSum;
}

template <typename T> int RollingAverage<T>::getNumSamplesTaken(){
  return numSamplesTaken;
}

template <typename T> T RollingAverage<T>::getLastNthSample(T n){
  int newIndex = sampleIndex;
  if( n <= numSamplesTaken ){
    if (sampleIndex < n){
      newIndex = numSamplesTaken - (n - sampleIndex);
    }
    else{
      newIndex = sampleIndex - n;
    }
    return sampleArray[newIndex];
  }
  else{return 0;}
  
}

template <typename T> int RollingAverage<T>::getSlope(){
  return(rollingAverage - previousRollingAverage);
}

template <typename T> int RollingAverage<T>::getAverage(){
  return rollingAverage;
}

template <typename T> int RollingAverage<T>::getMaxNumSamples(){
  return numSamples;
}

THIS IN ITSELF COMPILES FINE!
But when I instantiate an object of this in another class, lets call it SomeClass, and attempt to call member functios of RollingAverage, every member function call throws a compiler error:

Header:

class SomeClass{
  private:
    const int sensorAvgNumSamples{100};
    RollingAverage<int> sensorRollingAverage;

  public:
    SomeClass();
    void initialize(int sensorVal);
};

CPP file

SomeClass::SomeClass() 
//uses initializer list to construct objects using parameters
: sensorRollingAverage(RollingAverage<int>(sensorAvgNumSamples))
{
  //some code
}

void SomeClass::initialize(int sensorVal){
  if( sensorRollingAverage.getNumSamplesTaken() < sensorAvgNumSamples ){
        sensorRollingAverage.takeSample(sensorVal);
  }
}

Each call to a RollingAverage member function gets:

 undefined reference to `RollingAverage<int>::getNumSamplesTaken()'

Or whichever function is being called.

Sketch code if it matters:

SomeClass someClass;
int num;

void setup() {
  someClass.initialize(3);}

void loop() {  }

The errors include the constructor calls in the initialization list for SomeClass. These aren't specifically causing the problem because that initialization list works great for the non-template version of RollingAverage.

Any help would be appreciated. As always I apologize for my total noobnes at C++. If you need more/less context let me know.

Template functions, classes and methods should be implemented in the header. The compiler needs to have access to the implementation at the time of instantiation.

If you really want to keep the definition and implementation separated, you could #include the implementation at the end of the header file instead.

1 Like

Looks like that worked! Fantastic, thank you.
#including the cpp file at the end of the header didn't compile though.

That probably is because of the build system. Perhaps rename it to .tcc to avoid the implementation to be compiled twice.

I never use this myself though.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.