(SOLVED) Passing array size and values into object made from class

Hello!
So far, I've been making arrays and placing data outside of class, like here for example;

const byte ARRAY_SIZE = 3;
const byte ARRAY_SIZE2 = 9;
byte dataArray[ARRAY_SIZE];
byte dataArray2[ARRAY_SIZE2];

char arrayData[20];

void setup() {
  for (byte i = 0; i < sizeof(dataArray); i++) {
    //Just filling in array with some data
    dataArray[i] = i;
  }

  for (byte i = 0; i < sizeof(dataArray2); i++) {
    //Just filling in array with some data
    dataArray2[i] = i;
  }
  Serial.begin(115200);
}

void loop() {
  delay(1000);
  sprintf(arrayData, "%s%d", "Size of array1: ", sizeof(dataArray));
  Serial.println(arrayData);

  Serial.print(F("Data in array1: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');


  sprintf(arrayData, "%s%d", "Size of array2: ", sizeof(dataArray2));
  Serial.println(arrayData);

  Serial.print(F("Data in array2: "));
  for (byte i = 0; i < sizeof(dataArray2); i++) {
    Serial.print(dataArray2[i]);
  }
  Serial.println('\n');
}

But when I try to make class which object array size can be adjusted when creating object, I'm not having much luck.

So far, I've found methods of using, and also tried. Codes are attached into this post what Iv'e tried.
-Template
-#Define
-Pointer

I've never used templates, so they are bit confusing at this point; yet using them Is just fine.
Thinking about #define, I haven't found method of using #define with many objects with variable values. Like here, #define works with two arrays, but passing different #define values into class escapes me;

#define ARRAY_SIZE 5
#define ARRAY_SIZE2 8
byte dataArray[ARRAY_SIZE];
byte dataArray2[ARRAY_SIZE2];

char arrayData[20];

void setup() {
  for (byte i = 0; i < sizeof(dataArray); i++) {
    //Just filling in array with some data
    dataArray[i] = i;
  }

  for (byte i = 0; i < sizeof(dataArray2); i++) {
    //Just filling in array with some data
    dataArray2[i] = i;
  }
  Serial.begin(115200);
}

void loop() {
  delay(1000);
  sprintf(arrayData, "%s%d", "Size of array1: ", sizeof(dataArray));
  Serial.println(arrayData);

  Serial.print(F("Data in array1: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');


  sprintf(arrayData, "%s%d", "Size of array2: ", sizeof(dataArray2));
  Serial.println(arrayData);

  Serial.print(F("Data in array2: "));
  for (byte i = 0; i < sizeof(dataArray2); i++) {
    Serial.print(dataArray2[i]);
  }
  Serial.println('\n');
}

Now then, progress of making actual class is now this. This is using pointers, but it escapes me why object doesn't get correct size & data passed.

class arrayInClass {
public:
  arrayInClass::arrayInClass(byte* dataArray, byte arraySize, char* arrayName) {
    _arraySize = arraySize;
    _dataArray = dataArray;
    _arrayName = arrayName;
  }

  byte getArraySize() {
    return sizeof(_dataArray);
  }

  char* getArrayName() {
    return _arrayName;
  }

  byte getArrayValue(byte arrayIndex) {
    return _dataArray[arrayIndex];
  }

private:
  byte _arraySize;
  byte* _dataArray;
  char* _arrayName;
};

const byte ARRAY_SIZE = 10;
byte dataArray[ARRAY_SIZE];

arrayInClass newArray(dataArray, ARRAY_SIZE, "newArray");
char objectData[100];

void setup() {
  for (byte i = 0; i < ARRAY_SIZE; i++) {
    //Just filling in array with some data
    dataArray[i] = i;
  }
  Serial.begin(115200);
}



void loop() {
  delay(1000);
  //First reading what's going in;
  sprintf(objectData, "%s%s", "Object name: ", newArray.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array going in: ", sizeof(dataArray));
  Serial.println(objectData);

  Serial.print(F("Data of array going in: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');
  //Next reading what actually is in object;

  sprintf(objectData, "%s%d", "Size of array in object: ", newArray.getArraySize());
  Serial.println(objectData);

  Serial.print(F("Data of array in object: "));
  for (byte i = 0; i < newArray.getArraySize(); i++) {
    Serial.print(newArray.getArrayValue(i));
  }
  Serial.println('\n');
}

Serial output is as following;

Object name: newArray
Size of array going in: 10
Data of array going in: 0123456789

Size of array in object: 2
Data of array in object: 01

Here is my attempt of using #define, but it doens't like it

class arrayInClass {
public:
  arrayInClass::arrayInClass(byte* dataArray, byte arraySize, char* arrayName) {

#define _arraySize arraySize
    _dataArray = dataArray;
    _arrayName = arrayName;
  }

  byte getArraySize() {
    return sizeof(_dataArray);
  }

  char* getArrayName() {
    return _arrayName;
  }

  byte getArrayValue(byte arrayIndex) {
    return _dataArray[arrayIndex];
  }

private:
#define _arraySize 3
  byte _dataArray[_arraySize];
  char* _arrayName;
};

const byte ARRAY_SIZE = 10;
byte dataArray[ARRAY_SIZE];

arrayInClass newArray(dataArray, ARRAY_SIZE, "newArray");
char objectData[100];

void setup() {
  for (byte i = 0; i < ARRAY_SIZE; i++) {
    //Just filling in array with some data
    dataArray[i] = i;
  }
  Serial.begin(115200);
}



void loop() {
  delay(1000);
  //First reading what's going in;
  sprintf(objectData, "%s%s", "Object name: ", newArray.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array going in: ", sizeof(dataArray));
  Serial.println(objectData);

  Serial.print(F("Data of array going in: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');
  //Next reading what actually is in object;

  sprintf(objectData, "%s%d", "Size of array in object: ", newArray.getArraySize());
  Serial.println(objectData);

  Serial.print(F("Data of array in object: "));
  for (byte i = 0; i < newArray.getArraySize(); i++) {
    Serial.print(newArray.getArrayValue(i));
  }
  Serial.println('\n');
}

It gives following error, which I don't understand. I didn't touch array datatype at least on purpose

C:\Users\Atte\Desktop\arduino variable array size\arrayInClassDefine\arrayInClassDefine.ino: In constructor 'arrayInClass::arrayInClass(byte*, byte, char*)':
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassDefine\arrayInClassDefine.ino:6:18: error: incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte [3] {aka unsigned char [3]}'
     }
                  ^        

exit status 1

Compilation error: incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte [3] {aka unsigned char [3]}'

And finally, with template, which is new beast for me;

template<byte arraySize>
class arrayInClass {
public:
  arrayInClass::arrayInClass(byte* dataArray, byte arraySize, char* arrayName) {

    _arraySize = arraySize;
    _dataArray = dataArray;
    _arrayName = arrayName;
  }

  byte getArraySize() {
    return sizeof(_dataArray);
  }

  char* getArrayName() {
    return _arrayName;
  }

  byte getArrayValue(byte arrayIndex) {
    return _dataArray[arrayIndex];
  }

private:
  byte _arraySize;
  byte _dataArray[_arraySize];
  char* _arrayName;
};

const byte ARRAY_SIZE = 10;
byte dataArray[ARRAY_SIZE];

arrayInClass<ARRAY_SIZE> newArray(dataArray, ARRAY_SIZE, "newArray");
char objectData[100];

void setup() {
  for (byte i = 0; i < ARRAY_SIZE; i++) {
    //Just filling in array with some data
    dataArray[i] = i;
  }
  Serial.begin(115200);
}



void loop() {
  delay(1000);
  //First reading what's going in;
  sprintf(objectData, "%s%s", "Object name: ", newArray.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array going in: ", sizeof(dataArray));
  Serial.println(objectData);

  Serial.print(F("Data of array going in: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');
  //Next reading what actually is in object;

  sprintf(objectData, "%s%d", "Size of array in object: ", newArray.getArraySize());
  Serial.println(objectData);

  Serial.print(F("Data of array in object: "));
  for (byte i = 0; i < newArray.getArraySize(); i++) {
    Serial.print(newArray.getArrayValue(i));
  }
  Serial.println('\n');
}


Gives even bigger error

C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:4:57: error: declaration of 'const byte arraySize' shadows template parameter
   arrayInClass::arrayInClass(byte* dataArray, byte arraySize, char* arrayName) {
                                                         ^~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:1:10: note: template parameter 'arraySize' declared here
 template<byte arraySize>
          ^~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:4:83: error: explicit specialization of 'arrayInClass<arraySize>::arrayInClass(byte*, byte, char*)' must be introduced by 'template <>'
   arrayInClass::arrayInClass(byte* dataArray, byte arraySize, char* arrayName) {
                                                                                   ^
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:25:19: error: invalid use of non-static data member 'arrayInClass<arraySize>::_arraySize'
   byte _dataArray[_arraySize];
                   ^~~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:24:8: note: declared here
   byte _arraySize;
        ^~~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino: In member function 'byte arrayInClass<arraySize>::getArraySize()':
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:12:19: error: '_dataArray' was not declared in this scope
     return sizeof(_dataArray);
                   ^~~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino: In member function 'byte arrayInClass<arraySize>::getArrayValue(byte)':
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:20:12: error: '_dataArray' was not declared in this scope
     return _dataArray[arrayIndex];
            ^~~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino: At global scope:
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:32:68: error: no matching function for call to 'arrayInClass<10>::arrayInClass(byte [10], const byte&, const char [9])'
 arrayInClass<ARRAY_SIZE> newArray(dataArray, ARRAY_SIZE, "newArray");
                                                                    ^
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note: candidate: arrayInClass<10>::arrayInClass()
 class arrayInClass {
       ^~~~~~~~~~~~
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note:   candidate expects 0 arguments, 3 provided
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note: candidate: constexpr arrayInClass<10>::arrayInClass(const arrayInClass<10>&)
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note:   candidate expects 1 argument, 3 provided
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note: candidate: constexpr arrayInClass<10>::arrayInClass(arrayInClass<10>&&)
C:\Users\Atte\Desktop\arduino variable array size\arrayInClassTemplate\arrayInClassTemplate.ino:2:7: note:   candidate expects 1 argument, 3 provided

exit status 1

Compilation error: declaration of 'const byte arraySize' shadows template parameter

I believe that's all info and what I've tried. I have feeling that it should be easy to do, but obviously method has eluded me. Also I might have used wrong terminology here and there.

you would need to either use a template

template<typename T, size_t N>
class ArrayClass {
  private:
    T array[N];

  public:
    // Constructor to initialize the array
    ArrayClass() {
      for (size_t i = 0; i < N; ++i) {
        // Initializing each element to a default value
        array[i] = T();
      }
    }

    // Function to set a value at a specific index
    bool set(size_t index, const T& value) {
      if (index < N) {
        array[index] = value;
        return true;
      }
      return false;
    }

    // Function to get a value at a specific index
    T get(size_t index) const {
      if (index < N) {
        return array[index];
      }
      return T();
    }

    // Function to get the size of the array
    size_t size() const {
      return N;
    }
};

ArrayClass<byte, 5> byteArray;

void setup() {
  Serial.begin(115200);
  byteArray.set(0, 10);
  byteArray.set(1, 20);
  byteArray.set(2, 30);
  byteArray.set(3, 40);
  byteArray.set(4, 50);

  for (size_t i = 0; i < byteArray.size(); ++i) {
    Serial.print(i); Serial.write('\t'); Serial.println(byteArray.get(i));
  }
}

void loop() {}

or dynamic memory allocation with malloc in the class constructor

class ArrayClass {
private:
    byte* array;
    size_t size;

public:
    ArrayClass(size_t n) : size(n) {
        array = (byte*)malloc(sizeof(byte) * size);
        if (array == nullptr) {
            // Handle memory allocation failure
        } else {
            memset(array, 0, sizeof(byte) * size);
        }
    }

    ~ArrayClass() {
        free(array);
    }

    bool set(size_t index, byte value) {
        if (index < size) {
            array[index] = value;
            return true;
        }
        return false;
    }

    byte get(size_t index) const {
        if (index < size) {
            return array[index];
        }
        return 0; // Return 0 if index is out of bounds
    }

    size_t getSize() const {
        return size;
    }
};

ArrayClass byteArray(5);

void setup() {
    Serial.begin(115200);
    byteArray.set(0, 10);
    byteArray.set(1, 20);
    byteArray.set(2, 30);
    byteArray.set(3, 40);
    byteArray.set(4, 50);

    for (size_t i = 0; i < byteArray.getSize(); ++i) {
        Serial.print(i); Serial.write('\t'); Serial.println(byteArray.get(i));
    }
}

void loop() {}


EDIT:

To ensure that the rule is respected here are the copy constructor and an assignment operator.

    // Copy constructor
    ArrayClass(const ArrayClass& other) : size(other.size) {
        array = (byte*)malloc(sizeof(byte) * size);
        if (array == nullptr) {
            // Handle memory allocation failure (arduino does not raise exceptions)
        } else {
            memcpy(array, other.array, sizeof(byte) * size);
        }
    }

    // Assignment operator
    ArrayClass& operator=(const ArrayClass& other) {
        if (this != &other) {
            if (size != other.size) {
                // If sizes are different, reallocate memory
                size = other.size;
                free(array);
                array = (byte*)malloc(sizeof(byte) * size);
                if (array == nullptr) {
                    // Handle memory allocation failure (arduino does not raise exceptions)
                }
            }
            // Copy the contents
            memcpy(array, other.array, sizeof(byte) * size);
        }
        return *this;
    }

First, forget about using #define. That's just a simple text substitution and is useless for this application.

Next, which Arduino board are you compiling for? My answer may change if you're using an ESP32/8266 or ARM-based board.

Do you want the array to be external in the main code or internal to the class object?

Posting just the class code is not enough information. You must also post the main code that attempts to use the class object.

Thanks for Reply! I got it working while ago with template and will post working code later. As for malloc, I gotta research about this new method for me

Good point about board; It's arduino UNO.

Array can be internal, or external, but internal used in class might make code cleaner, but in same time harder to read in future because array is hidden from main view, but since It's declared anyway in plain view, it's not big deal.

As for full code, I think I copied various methods I tried; code snippets involving class definitons as well as setup() and loop().

Idea of tackling this problem was with led segment library I made while ago to make it more flexible in terms of array size.

Or are we talking about something else?

OK, that rules out the use of STL Containers.

Sorry, I missed it, you're right.

It's an important question that you should answer early in your design. Who creates and controls this array of leds? Your main code? The class object? The answer will tell you where the array belongs. Both paradigms have their uses.

This violates the rule of 0/5/3, it will cause a double free if you create any (accidental) copies of your ArrayClass.

Hello!

I'm not sure about what to answer about whether class or main code controls object array size.
currently, library creates object in syntax;

SevenSegment sevenSegmentDisplay(SPIChipSelectPin);

and if implementation of template works, it would turn to

SevenSegment<arraySize> sevenSegmentDisplay(SPIChipSelectPin);

So I think answer is main code, since class would only pass values to object?

Also, here's latest code, bit messy due debugging prints. Also there's no protection about going out bounds of array, and maybe other issues I'm not aware of.

template<byte arraySize>
class arrayInClass {
  public:
    arrayInClass(char* arrayName) {
      _arrayName = arrayName;
    };

    char* getArrayName() {
      return _arrayName;
    }

    void setArrayData(byte arrayIndex, byte arrayDataIn) {
      dataArray[arrayIndex] = arrayDataIn;
    }

    byte getArrayData(byte arrayIndex) {
      return dataArray[arrayIndex];
    }

    byte getArraySize() {
      return sizeof(dataArray);
    }

    byte dataArray[arraySize];

  private:

    char* _arrayName;
};

const byte arraySize = 10;
const byte arraySize2 = 5;
byte dataArray[arraySize];
byte dataArray2[arraySize2];
arrayInClass<arraySize> newArray("newArray");
arrayInClass<arraySize2> newArray2("newArray2");


char objectData[100];


void setup() {
  for (byte i = 0; i < newArray.getArraySize(); i++) {
    dataArray[i] = i * 3;
  }

  for (byte i = 0; i < newArray2.getArraySize(); i++) {
    dataArray2[i] = i * 4;
  }


  for (byte i = 0; i < newArray.getArraySize(); i++) {
    newArray.setArrayData(i, dataArray[i]);
  }

  for (byte i = 0; i < newArray2.getArraySize(); i++) {
    newArray2.setArrayData(i, dataArray2[i]);
  }


  Serial.begin(115200);
}

void loop() {
  delay(250);

  dataArray[0] = millis() / 100 % 10;
  newArray.setArrayData(0, dataArray[0]);

  dataArray2[1] = millis() / 100 % 10;
  newArray2.setArrayData(1, dataArray2[1]);


  //Serial.println("Reading what is wanted to go in");
  sprintf(objectData, "%s%s", "Reading what is wanted to go in: ", newArray.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array going in: ", sizeof(dataArray));
  Serial.println(objectData);

  Serial.print(F("Data of array going in: "));
  for (byte i = 0; i < sizeof(dataArray); i++) {
    Serial.print(' ');
    Serial.print(dataArray[i]);
  }
  Serial.println('\n');

  sprintf(objectData, "%s%s", "Next reading what actually is in object: ", newArray.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array in object: ", newArray.getArraySize());
  Serial.println(objectData);

  Serial.print(F("Data of array in object: "));
  for (byte i = 0; i < newArray.getArraySize(); i++) {
    Serial.print(' ');
    Serial.print(newArray.getArrayData(i));
  }
  Serial.println('\n');




  sprintf(objectData, "%s%s", "Reading what is wanted to go in: ", newArray2.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array going in: ", sizeof(dataArray2));
  Serial.println(objectData);


  Serial.print(F("Data of array going in: "));
  for (byte i = 0; i < sizeof(dataArray2); i++) {
    Serial.print(' ');
    Serial.print(dataArray2[i]);
  }
  Serial.println('\n');

  sprintf(objectData, "%s%s", "Next reading what actually is in object: ", newArray2.getArrayName());
  Serial.println(objectData);

  sprintf(objectData, "%s%d", "Size of array in object: ", newArray2.getArraySize());
  Serial.println(objectData);

  Serial.print(F("Data of array in object: "));
  for (byte i = 0; i < newArray2.getArraySize(); i++) {
    Serial.print(' ');
    Serial.print(newArray2.getArrayData(i));
  }
  Serial.println('\n');

}

Alright, started to wrap the previous code into library and for some reason template doesn't like when split to .cpp and .h files

First how it does work; functions declared in .h file;
.ino

#include <arraySizeInClass.h>

arraySizeInClass<3> newArray("newArray");


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

void loop() {
  delay(1000);
  Serial.println(newArray.getArrayName());
  Serial.println(newArray.getArraySize());
}

}

.cpp

#include <Arduino.h>
#include "arraySizeInClass.h"

.h

#ifndef arraySizeInClass_h
#define arraySizeInClass_h
#include <Arduino.h>

template <byte _arraySize>
class arraySizeInClass
{
public:
    arraySizeInClass(char *arrayName)
    {
        _arrayName = arrayName;
    };

    char *getArrayName()
    {
        return _arrayName;
    }

    byte getArraySize()
    {
        return sizeof(_dataArray);
    }

private:
    char *_arrayName;
    byte _dataArray[_arraySize];
};
#endif

BUT when I start splitting functions to .cpp;
.h file

#ifndef arraySizeInClass_h
#define arraySizeInClass_h
#include <Arduino.h>

template <byte _arraySize>
class arraySizeInClass
{
public:
    arraySizeInClass(char *_arrayName);
    char *getArrayName()
    {
        return _arrayName;
    }

    byte getArraySize()
    {
        return sizeof(_dataArray);
    }

private:
    char *_arrayName;
    byte _dataArray[_arraySize];
};
#endif

.cpp file

#include <Arduino.h>
#include "arraySizeInClass.h"

arraySizeInClass::arraySizeInClass(char *arrayName)
{
    _arrayName = arrayName;
};

ino.

#include <arraySizeInClass.h>

arraySizeInClass<3> newArray("newArray");


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

void loop() {
  delay(1000);
  Serial.println(newArray.getArrayName());
  Serial.println(newArray.getArraySize());
}

gives error

c:\Users\Atte\Documents\Arduino\libraries\arraySizeInClass\arraySizeInClass.cpp:4:1: error: invalid use of template-name 'arraySizeInClass' without an argument list
 arraySizeInClass::arraySizeInClass(char *arrayName)
 ^~~~~~~~~~~~~~~~
c:\Users\Atte\Documents\Arduino\libraries\arraySizeInClass\arraySizeInClass.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\Atte\Documents\Arduino\libraries\arraySizeInClass\arraySizeInClass.cpp:2:0:
c:\Users\Atte\Documents\Arduino\libraries\arraySizeInClass\arraySizeInClass.h:6:7: note: 'template<unsigned char _arraySize> class arraySizeInClass' declared here
 class arraySizeInClass
       ^~~~~~~~~~~~~~~~

exit status 1

Compilation error: exit status 1

Back to drawing board!
I use arduino 2.3.2 and visual studio code.

Don't split them up. Templates belong in a header file.

Well that explains it! Is there any method of splitting functions to .cpp just to keep things more readable, and is there any need for .cpp if template is being used?

// myclass.hpp
#pragma once

template <class T>
class MyClass {
  public:
    void foo();
};

#include "myclass.tpp"
// myclass.tpp
#pragma once
#include "myclass.hpp"

template <class T>
void MyClass<T>::foo() {
    // ...
}

Note that file names, file extensions, and the way classes and functions are distributed across files are all just a matter of convention. The language doesn't care where a function is declared or defined, as long as it's declared before it's used, and there is exactly one definition available for each function (either inline in a header file, or in an implementation file somewhere).

There are cases where you may want a .cpp file for your template class, see e.g. "extern template", but in most cases, everything is defined in a header (either directly, or by including a .tpp file with definitions in the header).

Thanks, I tried to implement Idea of using .tpp and .hpp files instead of .h and .cpp (or only .h actually in this case. Needless to say, using those new to me, and simple byte return function returns only default value what is set. Also it seems that template doesn't allow using char*
.ino

#include "myclass.hpp"
MyClass<3> foo;

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

void loop() {
  delay(1000);
  Serial.println(foo.getSize());
}

.hpp

// myclass.hpp
#pragma once

template <byte size>
class MyClass
{
public:
  void foo();
  byte getSize();

private:
  byte _size;
};

#include "myclass.tpp"

and .tpp

// myclass.tpp
#pragma once
#include "myclass.hpp"

template <byte size>
void MyClass<size>::foo()
{
    _size=size;
}

template <byte size>
byte MyClass<size>::getSize()
{
    return _size;
}

Any pointers what went wrong?

What do you mean? Of course templates allow char*.

There's no point in saving the size in a non-static member variable, you already know the size, it's size.

True - the example should have been more complete

Hmm, in that case I implemented it wrongly:

C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:3:22: error: '"newArray"' is not a valid template argument for type 'char*' because string literals can never be used in this context
 MyClass<3, "newArray"> foo;
                      ^
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino: In function 'void loop()':
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:12:22: error: request for member 'getSize' in 'foo', which is of non-class type 'int'
   Serial.println(foo.getSize());
                      ^~~~~~~
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:13:22: error: request for member 'getName' in 'foo', which is of non-class type 'int'
   Serial.println(foo.getName())
                      ^~~~~~~

exit status 1

Compilation error: '"newArray"' is not a valid template argument for type 'char*' because string literals can never be used in this context

.ino

#include "myclass.hpp"

MyClass<3, "newArray"> foo;


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

void loop() {
  delay(1000);
  Serial.println(foo.getSize());
  Serial.println(foo.getName());
}

.hpp

// myclass.hpp
#pragma once

template <byte size, char* name>
class MyClass
{
public:
  void foo();
  byte getSize();
  char* getName();
  
};

#include "myclass.tpp"

.tpp

// myclass.tpp
#pragma once
#include "myclass.hpp"

template <byte size, char *name>
void MyClass<size, name>::foo()
{
}

template <byte size, char *name>
byte MyClass<size, name>::getSize()
{
    return size;
}

template <byte size, char *name>
char *MyClass<size, name>::getName()
{
    return name;
}

I used same approach to save variable value like before into private variables inside class, which is why I used such method. Are variables defined in template already private by default?

"newArray" is a const char *

Oh? Interesting, I tried following as well, and it gives slighly different errors

char* name = "newArray";
MyClass<3, name> foo;

IDE shows it being char* as well

C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:4:16: error: 'name' is not a valid template argument because 'name' is a variable, not the address of a variable
 
                ^
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino: In function 'void loop()':
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:13:22: error: request for member 'getSize' in 'foo', which is of non-class type 'int'
   Serial.println(foo.getName());
                      ^~~~~~~
C:\Users\Atte\Documents\Arduino\libraries\myclass\examples\test\test.ino:14:22: error: request for member 'getName' in 'foo', which is of non-class type 'int'
 }
                      ^      

exit status 1

Compilation error: 'name' is not a valid template argument because 'name' is a variable, not the address of a variable

please, please never ever again post pictures of text... Not only they are not readable nor usable directly for copy&paste but they use up lots of storage and internet bandwidth which contributes to polluting the planet.

(I’m reading on my iPhone without my glasses so can’t see)

You need to use const char * for the parameter’s type and the member variable

This is incorrect as you can’t loose the const attribute (on some architectures the text will be stored in a non modifiable segment of flash memory)

Should be
const char* name = "newArray";

Otherwise +1 on @Delta_G comment. The name of your instance should be a parameter to the constructor probably.