Mehrere Arrays unbekannter Größe für eine Klasse

Herausforderung:
ich möchte einer Klasse zwei Arrays mit Pin Definitionen übergeben können.
Eins für Reihen Pins, eins für Spalten-Pins für ein LED-Multiplexing

Es soll nicht schon vorab eine Maximal-Größe dieser Arrays in der Klasse festgelegt werden.

Was ich durch bin:

  1. sind flexible array member nur am Ende der Klasse zulässig
    (ansonsten kommt ein flexible array member 'Led Matrix::output' not at end of 'class LedMatrix')
  2. Macht man mehrere flexible Arrays am Ende - das darf man nicht. Bekommt keine Warnung und sucht sich einen Wolf, warum man sich die Speicherbereiche überschreibt
  3. Aktuell habe ich halt zwei #defines gemacht und so eine Maximal-Größe der Arrays vorgegeben
    #define MATRIX_MAXCOLS 16
    #define MATRIX_MAXROWS 8

aber genau das wollte ich vermeiden. Außerdem seht ihr in der .h, eigentlich gibts noch ein drittes Array für einen output-buffer, den ich nur gem. Zeilenanzahl brauche
Gibts da eine einfache Lösung wie ich das dynamisch gestalten könnte, ohne dass ich Maximal-Größen vorab in der Klasse festlege?

Mini-Muster
Beispiel für eine 3x6 Pin Matrix
kompiliert bei mir für den Uno:

sketch.ino

#include "LedMatrix.h"

const uint8_t matrixColPin[]    // Only 02 - 13, A0 - A7 - otherwise adopt digitalWriteFast() or don't use it!,
{2, 3, 4, 5, 6, 7};

const uint8_t matrixRowPin[]
{A1, A2, A3};

LedMatrix display;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("Matrix Strandtest"));
  //helper
  const byte noOfCols = sizeof(matrixColPin) / sizeof(matrixColPin[0]);
  const byte noOfRows = sizeof(matrixRowPin) / sizeof(matrixRowPin[0]);
  //begin display
  display.begin(noOfCols, matrixColPin, noOfRows, matrixRowPin);
}

void loop() {
  // put your main code here, to run repeatedly:
  //delay(1000);  // testweise verlangsamen

  display.update();
}

LedMatrix.cpp

#include "LedMatrix.h"

void digitalWriteFast(uint8_t pin, uint8_t x)
// faster write without checks - use only on UNO, without PWM
// based on https://timodenk.com/blog/port-manipulation-and-arduino-digitalwrite-performance/
// added support for A0-A7 / Port C
{
  if (pin / 14) {
    PORTC ^= (-x ^ PORTC) & (1 << ((pin - 14) % 8)); // Analog-Pins
  }
  else if (pin / 8) {                                // pin >= 8 // 13..8
    PORTB ^= (-x ^ PORTB) & (1 << (pin % 8));
  }
  else {                                             // 7..0
    PORTD ^= (-x ^ PORTD) & (1 << (pin % 8));
  }
}

LedMatrix::LedMatrix()
{}

void LedMatrix::begin(const uint8_t _noOfCols, const uint8_t _colPin[], const uint8_t _noOfRows, const uint8_t _rowPin[])
{
  const uint8_t noOfCols = _noOfCols;
  const uint8_t noOfRows = _noOfRows;
  Serial.print(F("D035 noOfCols=")); Serial.println(noOfCols);
  Serial.print(F("D036 noOfRows=")); Serial.println(noOfRows);

  for (byte i = 0; i < noOfCols; i++)
  {
    colPin[i] = _colPin[i];
    Serial.print(colPin[i]); Serial.print(" ");
  }

  Serial.println();

  for (byte i = 0; i < noOfRows; i++)
  {
    rowPin[i] = _rowPin[i];                 
    Serial.print(rowPin[i]); Serial.print(" ");
  }

  Serial.print(F("\nD047 col pins:"));
  for (byte i = 0; i < noOfCols; i++)
  {
    pinMode(colPin[i], OUTPUT);
    digitalWrite(colPin[i], colOff);  
    Serial.print(colPin[i]); Serial.print(" ");
  }
  Serial.print(F("\nD055 row pins:"));
  for (byte i = 0; i < noOfRows; i++)
  {
    pinMode(rowPin[i], OUTPUT);
    digitalWrite(rowPin[i], rowOff);  
    Serial.print(rowPin[i]); Serial.print(" ");
  }
  Serial.println();
}

void LedMatrix::update(void)
{
  updateColWise();
}

void LedMatrix::updateColWise(void)
{
  static uint32_t previousTimestamp = 0;
  //static byte current = 0;                  // aktuelle Spalte
  uint32_t timestamp = micros();
  if (timestamp - previousTimestamp > 3500) // muss je nach cols/rows angepasst werden damit es nicht flackert (digitalWrite 500)
  {
    // tut noch nix - klar ;-)
    previousTimestamp = timestamp;
  }
}

LedMatrix.h

#pragma once
#include <Arduino.h>

#if defined(__AVR__)
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#endif

// MISSING 8bit, 16bit oder 32bit variablen

#define MATRIX_MAXCOLS 16           // böse, das soll weg
#define MATRIX_MAXROWS 8            // böse, das soll weg

void digitalWriteFast(uint8_t pin, uint8_t x);

class LedMatrix {
  public:
    LedMatrix();
    void begin(const uint8_t noOfCols, const uint8_t _colPin[], const uint8_t noOfRows, const uint8_t _rowPin[]);
    void update(void);                 // regelmäßiges Update des Displays (tick, run)

  private:
    void updateColWise(void);
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    const uint8_t noOfCols = 0;
    const uint8_t noOfRows = 0;
    uint16_t output[MATRIX_MAXROWS];    // böse, das soll nicht fixe Größe haben
    uint8_t colPin[MATRIX_MAXCOLS], rowPin[MATRIX_MAXROWS]; // böse, das soll nicht fixe Größe haben
};
template<int rows, int cols>
class LedMatrix 
{
   private:
   
     byte rowpins[rows];
     byte collpins[cols];

};


LedMatrix<8,16> matrix; // instanziierung

ungetestet

Alternativ:

template<typename CollType, typename RowType>
class LedMatrix
{
   private:
   
     RowType  rows;
     CollType cols;

};

using CollArray = byte[16];
using RowArray  = byte[8];

LedMatrix<CollArray,RowArray> matrix; // instanziierung

// LedMatrix<byte[16],byte[8]> matrix; // instanziierung

nö, nicht angekommen.

Wie übergebe ich da nun die Pins?

{2, 3, 4, 5, 6, 7};

und

{A1, A2, A3};

template<size_t size>
class Test
{
public:
 void print()
 {
  for (byte pin : pins)
    Serial.println(pin);
 }

 Test(byte* pins)
 {
  for (byte i = 0; i < size; i++)
    this->pins[i] = pins[i];
 }
private:
 byte pins[size];
};

void setup()
{
 Serial.begin(9600);

 byte pins[] = { 1, 2, 3, 4, 5 };
 Test<sizeof(pins)> test(pins);
 test.print();
}

void loop()
{
}

Man könnte auch in der Klasse nur eine Referenz auf das Array speichern

Wird zwar noch etwas dauern, aber es wird.

Danke an beide
Karma+

edit: da wird ein Schuh draus, das funktioniert ja super!
Momentan zwar nur geblinke, aber wenn ich das noch in meine Lib bekomm, perfekt.

template<size_t noOfCols, size_t noOfRows>
class Test
{
  public:
    void begin()
    {
      for (byte pin : colPin)
        pinMode(pin, OUTPUT);
      for (byte pin : rowPin)
        pinMode(pin, OUTPUT);
    }

    void print()
    {
      for (byte pin : colPin)
        Serial.println(pin);
      for (byte pin : rowPin)
        Serial.println(pin);
    }

    void blinkblink()
    {
      static uint32_t previousTimestamp = 0;
      uint32_t timestamp = millis();
      if (timestamp - previousTimestamp > 1000)
      {
        for (byte pin : colPin)
          digitalWrite(pin, colOff);
        for (byte pin : rowPin)
          digitalWrite(pin, rowOff);
        byte myCol = random(noOfCols);
        byte myRow = random(noOfRows);
        Serial.print(F("myCol="));Serial.print(myCol);Serial.print(F("   myRow="));Serial.println(myRow);
        digitalWrite(colPin[myCol], colOn);
        digitalWrite(rowPin[myRow], rowOn);
        previousTimestamp = timestamp;
      }
    }

    Test(byte* colPin, byte* rowPin)
    {
      for (byte i = 0; i < noOfCols; i++)
        this->colPin[i] = colPin[i];
      for (byte i = 0; i < noOfRows; i++)
        this->rowPin[i] = rowPin[i];
    }

  private:
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    uint8_t colPin[noOfCols];
    uint8_t rowPin[noOfRows];
};

/* Anwenderdefinition */
uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
uint8_t matrixRowPin[] {A1, A2, A3};
/* Ende der Anwenderdefinition */

Test<sizeof(matrixColPin), sizeof(matrixRowPin)> test(matrixColPin, matrixRowPin);  

void setup()
{
  Serial.begin(115200);
  test.begin();
  test.print();
}

void loop()
{
  test.blinkblink();
}

Tipp:
Da du die Arrays außerhalb der Klasse hältst, könntest du dem Konstruktor Referenzen übergeben.
Das spart die doppelte Datenhaltung und damit auch die Kopieraktion.

habe dem Konstruktor Referencen übergeben
die lokalen Variablen gelöscht(auskommentiert)

// Passing an array of unknown size by reference to constructor
// non working

template<size_t noOfCols, size_t noOfRows>
class Test
{
  public:
    void print()
    {
      for (byte pin : colPin)                        // sketch_nov26b:8:23: error: 'colPin' was not declared in this scope
        Serial.println(pin);
      for (byte pin : rowPin)
        Serial.println(pin);
    }

    Test(byte(&colPin)[noOfCols], byte(&rowPin)[noOfRows])
    {
      /*
      for (byte i = 0; i < noOfCols; i++)
        this->colPin[i] = colPin[i];
      for (byte i = 0; i < noOfRows; i++)
        this->rowPin[i] = rowPin[i];
      */
    }

  private:
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    //uint8_t colPin[noOfCols];
    //uint8_t rowPin[noOfRows];
};

/* Anwenderdefinition */
uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
uint8_t matrixRowPin[] {A1, A2, A3};
/* Ende der Anwenderdefinition */

Test<sizeof(matrixColPin), sizeof(matrixRowPin)> test(matrixColPin, matrixRowPin);  

void setup()
{
  Serial.begin(115200);
  test.print();
}

void loop()
{
}

das mag nicht kompilieren,
in der Methode habe ich keinen Zugriff mehr auf meine per Reference übergebenen Variablen

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino: In member function 'void Test<noOfCols, noOfRows>::print()':

sketch_nov26b:8:23: error: 'colPin' was not declared in this scope

for (byte pin : colPin)

^~~~~~

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino:8:23: note: suggested alternative: 'colOn'

for (byte pin : colPin)

^~~~~~

colOn

sketch_nov26b:10:23: error: 'rowPin' was not declared in this scope

for (byte pin : rowPin)

^~~~~~

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino:10:23: note: suggested alternative: 'rowOn'

for (byte pin : rowPin)

^~~~~~

rowOn

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino: In instantiation of 'Test<noOfCols, noOfRows>::Test(byte (&)[noOfCols], byte (&)[noOfRows]) [with unsigned int noOfCols = 6; unsigned int noOfRows = 3; byte = unsigned char]':

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino:38:81: required from here

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino:14:32: warning: unused parameter 'colPin' [-Wunused-parameter]

Test(byte(&colPin)[noOfCols], byte(&rowPin)[noOfRows])

^

C:\Daten\myrepository\Arduino\forum\sketch_nov26b\sketch_nov26b.ino:14:57: warning: unused parameter 'rowPin' [-Wunused-parameter]

Test(byte(&colPin)[noOfCols], byte(&rowPin)[noOfRows])

^

exit status 1
'colPin' was not declared in this scope

// Passing an array of unknown size by reference to constructor
// now working

template<typename Cols, typename Rows>
class Test: public Printable
{
  public:
    size_t  printTo(Print &print) const
    {
      size_t len = 0;
      for (byte pin : colPin)                        // sketch_nov26b:8:23: error: 'colPin' was not declared in this scope
        len += print.println(pin);
      for (byte pin : rowPin)
        len += print.println(pin);
      return len;  
    }

    Test(Cols &colPin,Rows &rowPin): colPin(colPin) , rowPin(rowPin)
    {
      /*
      for (byte i = 0; i < noOfCols; i++)
        this->colPin[i] = colPin[i];
      for (byte i = 0; i < noOfRows; i++)
        this->rowPin[i] = rowPin[i];
      */
    }

  private:
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    Cols &colPin;
    Rows &rowPin;
};

/* Anwenderdefinition */
const uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
const uint8_t matrixRowPin[] {A1, A2, A3};
/* Ende der Anwenderdefinition */

Test<decltype(matrixColPin),decltype(matrixRowPin)> test(matrixColPin, matrixRowPin); 

void setup()
{
  Serial.begin(9600);
  Serial.print(test);
}

void loop()
{
}

Nur korrigiert, nicht getestet.

habe dem Konstruktor Referencen übergeben

Das ist aber nicht das was gesagt wurde. Es ging eigentlich darum dass du in der Klasse nur eine Referenz speicherst und nicht das ganze Array

Das hatte ich auch als Alternative erwähnt:
"Man könnte auch in der Klasse nur eine Referenz auf das Array speichern"

Das man dann eine Referenz als Parameter übergeben muss ist die logische Konsequenz daraus. Aber nicht das Ziel

danke combie, #7 compiliert und läuft.
Ohne dem printable wird es kleiner als #4 (flash und RAM)

Jetzt muss ich noch ran, die Elemente richtig zu verteilen in .ino, .cpp, .h ... das scheint auch noch spannend zu werden.

(gestern hatte das Forum laufend 504er Fehler, daher erst so spät die Rückmeldung).

kann mir bitte wer behilflich sein, ich schaffe das Aufteilen in die tabs nicht.

Das Komplette kompiliert ohne Warning.

// Passing an array of unknown size by reference to constructor
// https://forum.arduino.cc/index.php?topic=650363.0
// now working

template<typename Cols, typename Rows>
class Test
{
  public:
    Test(Cols &colPin, Rows &rowPin): colPin(colPin) , rowPin(rowPin)
    {}

    void begin()
    {
      for (byte pin : colPin)
      {
        pinMode(pin, OUTPUT);
      }
      for (byte pin : rowPin)
      {
        pinMode(pin, OUTPUT);
      }
    }

    void blinkblink()
    {
      static uint32_t previousTimestamp = 0;
      uint32_t timestamp = millis();
      if (timestamp - previousTimestamp > 1000)
      {
        const uint8_t noOfCols = sizeof(colPin) / sizeof(colPin[0]);
        const uint8_t noOfRows = sizeof(rowPin) / sizeof(rowPin[0]);
        for (byte pin : colPin)
          digitalWrite(pin, colOff);
        for (byte pin : rowPin)
          digitalWrite(pin, rowOff);
        byte myCol = random(noOfCols);
        byte myRow = random(noOfRows);
        Serial.print(F("myCol=")); Serial.print(myCol); Serial.print(F("   myRow=")); Serial.println(myRow);
        digitalWrite(colPin[myCol], colOn);
        digitalWrite(rowPin[myRow], rowOn);
        previousTimestamp = timestamp;
      }
    }

  private:
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    Cols &colPin;
    Rows &rowPin;
};

/* Anwenderdefinition */
const uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
const uint8_t matrixRowPin[] {A1, A2, A3};
/* Ende der Anwenderdefinition */

Test<decltype(matrixColPin), decltype(matrixRowPin)> test(matrixColPin, matrixRowPin);

void setup()
{
  Serial.begin(115200);
  Serial.println(F("template reference in tabs"));
  test.begin();
}

void loop()
{
  test.blinkblink();
}

Aufteilung schaffe ich nicht:
Der Sketch.ino

// Passing an array of unknown size by reference to constructor
// https://forum.arduino.cc/index.php?topic=650363.0
// splitted into tabs

#include "matrix.h"

/* Anwenderdefinition */
const uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
const uint8_t matrixRowPin[] {A1, A2, A3};
/* Ende der Anwenderdefinition */

template<typename Cols, typename Rows>
Test<decltype(matrixColPin), decltype(matrixRowPin)> test(matrixColPin, matrixRowPin);

void setup()
{
  Serial.begin(115200);
  Serial.println(F("template reference in tabs"));
  test.begin();
}

void loop()
{
  test.blinkblink();
}

Die matrix.cpp

#include "matrix.h"

//template<typename Cols, typename Rows>
Test Test(Cols &colPin, Rows &rowPin): colPin(colPin) , rowPin(rowPin)
{}

void Test::begin()
{
  for (byte pin : colPin)
  {
    pinMode(pin, OUTPUT);
  }
  for (byte pin : rowPin)
  {
    pinMode(pin, OUTPUT);
  }
}

void Test::blinkblink()
{
  static uint32_t previousTimestamp = 0;
  uint32_t timestamp = millis();
  if (timestamp - previousTimestamp > 1000)
  {
    const uint8_t noOfCols = sizeof(colPin) / sizeof(colPin[0]);
    const uint8_t noOfRows = sizeof(rowPin) / sizeof(rowPin[0]);
    for (byte pin : colPin)
      digitalWrite(pin, colOff);
    for (byte pin : rowPin)
      digitalWrite(pin, rowOff);
    byte myCol = random(noOfCols);
    byte myRow = random(noOfRows);
    Serial.print(F("myCol=")); Serial.print(myCol); Serial.print(F("   myRow=")); Serial.println(myRow);
    digitalWrite(colPin[myCol], colOn);
    digitalWrite(rowPin[myRow], rowOn);
    previousTimestamp = timestamp;
  }
}

Die matrix.h

#pragma once
#include <Arduino.h>

template<typename Cols, typename Rows>
class Test
{
  public:
    Test(Cols &colPin, Rows &rowPin): colPin(colPin) , rowPin(rowPin)
    {}
    void begin();
    void blinkblink();

  private:
    const uint8_t rowOn = false;       // je nach Hardware: ich brauche geschaltes GND in der Reihe --> common row cathode (somit rowOn=false)
    const uint8_t rowOff = !rowOn;     // invers
    const uint8_t colOn = !rowOn;      // zur Reihe, ich brauch 5V auf der Spalte daher true
    const uint8_t colOff = !colOn;     // invers
    Cols &colPin;
    Rows &rowPin;
};

ich häng noch das Zip dran, falls sich jemand das copy/paste sparen will

sketch_nov26b_template_reference_tabs.zip (1.93 KB)

Separat die Fehler

C:\Daten\myrepository\Arduino\HW\matrix\sketch_nov26b_template_reference_tabs\sketch_nov26b_template_reference_tabs.ino:13:54: warning: variable templates only available with -std=c++14 or -std=gnu++14

 Test<decltype(matrixColPin), decltype(matrixRowPin)> test(matrixColPin, matrixRowPin);

                                                      ^~~~

C:\Daten\myrepository\Arduino\HW\matrix\sketch_nov26b_template_reference_tabs\sketch_nov26b_template_reference_tabs.ino: In function 'void setup()':

sketch_nov26b_template_reference_tabs:19:7: error: missing template arguments before '.' token

   test.begin();

       ^

C:\Daten\myrepository\Arduino\HW\matrix\sketch_nov26b_template_reference_tabs\sketch_nov26b_template_reference_tabs.ino: In function 'void loop()':

sketch_nov26b_template_reference_tabs:24:7: error: missing template arguments before '.' token

   test.blinkblink();

       ^

matrix.cpp:4:1: error: invalid use of template-name 'Test' without an argument list

 Test Test(Cols &colPin, Rows &rowPin): colPin(colPin) , rowPin(rowPin)

 ^~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:4:1: note: class template argument deduction is only available with -std=c++1z or -std=gnu++1z

In file included from C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:1:0:

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.h:5:7: note: 'template<class Cols, class Rows> class Test' declared here

 class Test

       ^~~~

matrix.cpp:7:6: error: 'template<class Cols, class Rows> class Test' used without template parameters

 void Test::begin()

      ^~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp: In function 'void begin()':

matrix.cpp:9:19: error: 'colPin' was not declared in this scope

   for (byte pin : colPin)

                   ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:9:19: note: suggested alternative: 'cli'

   for (byte pin : colPin)

                   ^~~~~~

                   cli

matrix.cpp:13:19: error: 'rowPin' was not declared in this scope

   for (byte pin : rowPin)

                   ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:13:19: note: suggested alternative: 'rewind'

   for (byte pin : rowPin)

                   ^~~~~~

                   rewind

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp: At global scope:

matrix.cpp:19:6: error: 'template<class Cols, class Rows> class Test' used without template parameters

 void Test::blinkblink()

      ^~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp: In function 'void blinkblink()':

matrix.cpp:25:37: error: 'colPin' was not declared in this scope

     const uint8_t noOfCols = sizeof(colPin) / sizeof(colPin[0]);

                                     ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:25:37: note: suggested alternative: 'cli'

     const uint8_t noOfCols = sizeof(colPin) / sizeof(colPin[0]);

                                     ^~~~~~

                                     cli

matrix.cpp:26:37: error: 'rowPin' was not declared in this scope

     const uint8_t noOfRows = sizeof(rowPin) / sizeof(rowPin[0]);

                                     ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:26:37: note: suggested alternative: 'rewind'

     const uint8_t noOfRows = sizeof(rowPin) / sizeof(rowPin[0]);

                                     ^~~~~~

                                     rewind

matrix.cpp:27:21: error: unable to deduce 'auto&&' from 'colPin'

     for (byte pin : colPin)

                     ^~~~~~

matrix.cpp:28:25: error: 'colOff' was not declared in this scope

       digitalWrite(pin, colOff);

                         ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:28:25: note: suggested alternative: 'modff'

       digitalWrite(pin, colOff);

                         ^~~~~~

                         modff

matrix.cpp:29:21: error: unable to deduce 'auto&&' from 'rowPin'

     for (byte pin : rowPin)

                     ^~~~~~

matrix.cpp:30:25: error: 'rowOff' was not declared in this scope

       digitalWrite(pin, rowOff);

                         ^~~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:30:25: note: suggested alternative: 'modff'

       digitalWrite(pin, rowOff);

                         ^~~~~~

                         modff

matrix.cpp:34:33: error: 'colOn' was not declared in this scope

     digitalWrite(colPin[myCol], colOn);

                                 ^~~~~

matrix.cpp:35:33: error: 'rowOn' was not declared in this scope

     digitalWrite(rowPin[myRow], rowOn);

                                 ^~~~~

C:\Users\werner\AppData\Local\Temp\arduino_build_944680\sketch\matrix.cpp:35:33: note: suggested alternative: 'rewind'

     digitalWrite(rowPin[myRow], rowOn);

                                 ^~~~~

                                 rewind

exit status 1
missing template arguments before '.' token

Was willst du mit dem Template in der ersten Zeile?

template<typename Cols, typename Rows>
Test<decltype(matrixColPin), decltype(matrixRowPin)> test(matrixColPin, matrixRowPin);

den Typ für &colPin &rowPin bekannt machen.

Das ist doch schon bekannt. Das steht direkt oben drüber:

const uint8_t matrixColPin[] { 2, 3, 4, 5, 6, 7 };
const uint8_t matrixRowPin[] {A1, A2, A3};

decltype nimmt den Typ dieser Arrays um das Template so instantiieren

So wie du das machst denkt der Compiler natürlich das wäre ein Variablen-Template und bringt einen Fehler. Steht so klar dort. Das mit Templates solltest du dir noch mal ansehen

Aufteilung schaffe ich nicht:

Hmmm ...

Verwende (bei template Klassen) nur *.h Dateien.
Nix *.cpp