I have a few thousand lines of code that I am trying to refactor, and I can reduce a lot of code reduplication by combining several of different classes into a single class that handles things by calls on a pointer to external friend classes.
I am running into a problem in that I have a variable num_var that counts a number of variables to be used in a calculation, and this changes depending on the external friend class. This number determined the size of many of my arrays. With the arrays, I often perform linear algebra with external functions, and these functions are template functions with the template parameter being the size of the array, num_var. I used to have this static, but I am no longer able to do that.
I now get an error like this:
candidate template ignored: invalid explicitly-specified argument for template parameter
Below is a very simple program that reduplicates the compiler error for a much simpler system:
#include <iostream>
enum Color {red=0, blue, green};
class Side {//the side of a shape, which can be a color
public:
Color color;
friend class Shape;
};
//this function adds numerical value of side colors and prints a value
template <size_t N> int sideNamer(Side sides[N]){
int count = 0;
for(int i=0; i<N; i++) count += sides[i].color;
std::cout << "My sides add to " << count << "\n";
return count;
};
class Shape { //can have an arbitrary number of sides, each a different color
public:
const int Nsides;
Side *sides;
//constructor sets the number of sides and gives a color to each side
Shape(int N, Color *colors) : Nsides(N){
sides = new Side[Nsides];
for(int i=0; i<Nsides; i++) sides[i].color = colors[i];
};
~Shape(){ delete[] sides;};
//name the sum of the sides
void nameMySides(){
sideNamer<Nsides>(sides);
}
};
int main(){
//make a triangle: should add to 3
Color myTriangleColors[3] = {red, blue, green};
Shape myTriangle(3, myTriangleColors);
myTriangle.nameMySides();
//make a square: should add to 2
Color mySquareColors[4] = {red, red, blue, blue};
Shape mySquare(4, mySquareColors);
mySquare.nameMySides();
}
This gives me the same error, about an invalid explicitly-specified argument for template parameter.
When I change the declaration of Shape to be a template class, as in
template <size_t N> class Shape {
public:
static const int Nsides = N;
Side *sides;
Shape(Color *colors) {
sides = new Side[Nsides];
for(int i=0; i<Nsides; i++) sides[i].color = colors[i];
};
~Shape(){ delete[] sides;};
void nameMySides(){
sideNamer<Nsides>(sides);
}
};
and mutando mutandis then there is no problem and it works. Sadly, I am not able to do this in my actual program because in some other place in the code I have another class that holds an array of pointers to "Shape" objects and I am not able to specify the `size_t' at that point in the code, so I can't be using templates there.
Is there something else I can do to make the template function work? Also, if it could permit me to declare the Side array as Side sides[Nsides] instead of as Side *sides that would also be greatly appreciated.
How do I work with the template argument when I can't use a template class or a static const? Or is there a way to make the template class work in the earlier part of the program? Do I just have to rewrite the linear algebra functions?
Thanks in advance.
(PS My actual class with the problem is called Mode, representing an eigenmode in a physical problem. It has a pointer to an abstract class called ModeDriver, and individual children of ModeDriver might have 2, 4, 8, ... variables, the number of which are stored in a variable called num_var. This changes based on physical properties of the particular waveform being modeled. Several different locations in the code make use of the linear algebra functions.)
I do not believe, nor remember the exact standardese term, that const int Nsides; is a valid argument to a template instantiation. That is what the compiler is trying to tell you and exactly what your change to making this a template itself fixes.
Related
I'm currently designing classes that should represent a chaotic storage system.
Lets say we have slots in rows and columns with certain properties.
So the slots have different restrictions in min/max height, width, length, weight and some more that come from a parameter file.
Also the Slots have a max total weight that must be checked before a new parcel gets added to that slot. And also the max weight that a row of slots can hold is lower than the sum of the max weights of the single slots. So for example each individual slot might be able to hold 50kg but the row of 10 slots must not exceed 200kg, so it is not allowed to fill every slot by 100%. The same is true for the Columns where the maximum weight is lower than the sum of the individual weights of the single rows. The row_id and column_id are atrificial numbers for adressing the slot in the physical system with barcodes or whatever that get read for positioning.
As all this parameters do not change over the lifetime of the program, my intention was to design the classes in a way that this properties are readable by getter functions but there should not be any setter functions (maybe not even private ones) in the object o the values cannot be changed by accident.
There is one class/function that reads the config-file and generates the data structure for the rows and columns with the slots. This function should be able to read the config and create objects for every column holding a row of slots and pass all the values from the config down to the slot.
Later when the program is running I also need some way to search for the best matching slot to add the next parcel or for searching parcels and unload them in a certain sequence.
So the (simplfied) basic structure of the classes would be like this:
Class Parcel {
int width;
int height;
int length;
int weight;
}
Class Slot {
vector<Parcel> parcel;
int min_width;
int max_width;
int min_height;
int max_height;
int min_length;
int max_length;
int max_total_weight;
int act_total_weight;
int total_length;
int free_length;
}
Class Row {
vector<Slot> slot;
int row_id;
int max_total_weight;
int act_total_weight;
}
Class Column {
vector<Row> row;
int column_id;
int max_total_weight;
int act_total_weight;
}
Class Storage {
vector<Column> column;
}
So here are my thoughts about how to initialize the data structure:
First possibility would be to pass all the properties in the constructor(s) of the classes, but then the constructors has some huge parameter lists specially for the Slot class that has a lot of properties.
Second thing that came to my mind (and currently my fafourite way to go) is to use config-data-structures that hold all the parameters. This parameter-objects get filled by the config-function and passed to the constructor when initializing the class. Then it also may be useful to use the parameter class as such and not having all the parameters defined in the storage class once more.
Third way is to use private setter and public getter and make the config class friends with the data structure classes to be able to access the setter functions (but i would prefer to have no setters at all in the final storage structure classes.
Fourth way that i was thinking off, was to derive child classes from the structure classes that hold the setter functions (and also some other logic needed for creating the data structure) so the child has no own variables but only additional functions. So the child class is used to fill the properties but the base class gets added to the data structure vector.
I also want to use Factory pattern to initialize the data structure because the objects have often similar or only slightly different properties. So with the second aproach after creating one row of slots I would maybe want to change the max weight of the slots in that row. Therefore I would need to change the setting in the factory and the factory then fills the parameter data structure differently and passes it to the Slot class. Or is it better to pass the data structure to the factory directly and the factory assigns it but then i think this is not what the factory pattern is meant to be.
I don't know if this is a good aproach or which of the above is best practice.
Or am I missing something and there is a way more convenient solution or this?
Thank you (and sorry if the question is maybe not the way it should be)
When constructing your classes as you describe it you can have a look at the creational design patterns.
Your second proposed solution is almost a builder design pattern. This will help you to construct the Slot e.g. piecewise.
As an example:
#include <iostream>
class Slot {
public:
int GetMinWidth() const { return min_width_; };
int GetMaxWidth() const { return max_width_; };
// Builder class
class SlotBuilder {
public:
SlotBuilder& SetMinWidth(int min_width) {
min_width_ = min_width;
return *this;
}
SlotBuilder& SetMaxWidth(int max_width) {
max_width_ = max_width;
return *this;
}
Slot Build() {
return Slot(min_width_, max_width_);
}
private:
int min_width_{/* you can add default value here*/};
int max_width_{/* you can add default value here*/};
};
// This is optional, but creates a neat interface
static SlotBuilder Create() {
static SlotBuilder slot_builder;
return slot_builder;
}
private:
// Make constructor private to restrict access and force the use of the builder
Slot(int min_width, int max_width) : min_width_(min_width), max_width_(max_width) {}
const int min_width_;
const int max_width_;
// .
// .
// Continue with your const attributes
};
int main() {
// Create the slot with the builder
Slot slot = Slot::Create()
.SetMinWidth(10)
.SetMaxWidth(20)
.Build();
std::cout << slot.GetMinWidth() << ", " << slot.GetMaxWidth();
return 0;
}
You can see the example working here
For having different types that are almost the same a Prototype pattern could work if you want to "clone" a class or in your case a Factory pattern could do the job.
There is never an ideal solution or that one pattern that solves it all, so I can't give you a definitive answer, but here are some collected thoughts:
Default values
Primitive types like int don't have a default value, so make sure you give them one explicitly:
struct Parcel {
int width{};
int height = 0;
int length = {};
int weight{};
}
All those different versions above are equivalent, but you really should use one of them. Otherwise you will probably run into UB down the line.
Const correctness
One thing that I love about C++ and that I dearly miss in languages like C# is const correctness. If you want an object to be immutable, declare it as const. To prevent changes to your objects, either instantiate the object as a const:
const Parcel x;
x.width = 10; // compiler error
or make the members of your classes const:
struct Parcel {
const int width{};
const int height{};
const int length{};
const int weight{};
};
Parcel x;
x.width = 10; // compiler error
Aggregate initialization
If you keep your types simple enough you can initialize the class members with curly braces directly:
const Parcel x { 1, 2, 3, 4 };
In C++ 20, you can also name the members, so this code is equivalent to the line above:
const Parcel x { .width = 1, .height = 2, .length = 3, .weight = 4 };
Note that this can bite you later though if you have to deal with ABI stability and versioning. In that case you are better off using getter and setter functions, because that allows you to still change the data layout of your members.
I have to think about design patterns a bit more. I'll update this post if something useful comes out of it.
I'm writing an Arduino library to wrap the pin functions (digitalRead, digitalWrite, analogRead, etc.). For example, I have a RegularPin class which is a passthrough and an InvertedPin class which inverts the pin logic. This is useful when going from the breadbord with LEDs to a relay board which inverts the circuit logic. I just have to swap classes.
I also have a DebouncedPin class for buttons which checks the user presses or releases long enough for the button to be really pressed/released.
Example for analog pins:
// AnalogInPin ------------------------------
class AnalogInPin
{
public:
virtual int read()=0;
virtual int getNo()=0;
};
// AnalogRegInPin ---------------------------
template<int pinNo>
class AnalogRegInPin : public AnalogInPin
{
public:
AnalogRegInPin();
int read();
int getNo(){return pinNo;}
};
template<int pinNo>
int AnalogRegInPin<pinNo>::read()
{
return analogRead(pinNo);
}
template<int pinNo>
AnalogRegInPin<pinNo>::AnalogRegInPin()
{
pinMode(pinNo, INPUT);
}
As you can see, I put the pin number in the template declaration because it is not to be changed at run time and I do not want the pin number to use memory when I allocate a pin object, just like in vanilla arduino C code. I know classes can not be of size zero but read on. Next, I want to write an "AveragedPin" class which will automatically read the selected pin several times and I would like to stack my templated classes like this :
AveragedPin<cAnalogRegInPin<A0>, UPDATE_ON_READ|RESET_ON_READ> ava0;
or even :
RangeCorrectedPin<AveragedPin<cAnalogRegInPin<A0>,
UPDATE_ON_READ|RESET_ON_READ,RAW_MIN,RAW_MAX,TARGET_RANGE> rcava0;
For the time being, I declared the nested pin as a private member because it is not allowed to use a class object in the template declaration. But then, each layer of nesting uselessly eats several bytes on the stack.
I know I could use references in the template declaration, but I don't quite understand how that works/should be used. My problem looks like empty member optimization, but it doesn't seem to apply here.
I feel this is more a C++ question than an arduino one and I'm not a C++ expert. I guess this touches the more advanced parts of C++. Maybe what I want is not possible, or only with recent C++ (20?) revisions.
Below is the code for the FixedRangeCorrectedPin class.
template <class P, int rawMin, int rawMax, int targetRange>
class FixedRangeCorrectedPin : public AnalogInPin
{
public:
int read();
int getNo(){return pin.getNo();}
private:
P pin;
};
template <class P, int rawMin, int rawMax, int targetRange>
int FixedRangeCorrectedPin<P, rawMin, rawMax, targetRange>::read()
{
int rawRange = rawMax - rawMin;
long int result = pin.read() - rawMin;
if (result < 0) result = 0;
result = result * targetRange / rawRange;
if (result > targetRange) result = targetRange;
return result;
}
My problem is that I would like to remove the 'P pin' class member and replace it in the template declaration like in template <AnalogInPin pin,int rawMin,int rawMax,int targetRange> because which pin is involved here is completely known at compile time.
As you can see, I put the pin number in the template declaration because it is not to be changed at run time and I do not want the pin number to use memory when I allocate a pin object, just like in vanilla arduino C code.
OK, if the pin number is a compile-time constant as it usually is for Arduino, this bit is fine.
However, making the AnalogInPin base class abstract (ie, adding virtual methods) will in practice use at least as much space per object as you saved by not storing the pin as an integer.
The details are implementation-specific, but runtime polymorphism requires some way of figuring out, for a given derived-class object pointed to by an AnalogInPin*, which version of the virtual methods to call, and that requires storage in each object of derived type. (You can verify that this is true buy just checking sizeof(AnalogInPin) and comparing to sizeof an otherwise identical class with no virtual methods.
I know classes can not be of size zero but ...
There's an special case for base classes with no data members that allows them to take no extra size (an instance of the most-derived type must still occupy at least one byte). It's called the empty base class optimization.
For the time being, I declared the nested pin as a private member because it is not allowed to use a class object in the template declaration. But then, each layer of nesting uselessly eats several bytes on the stack.
We can flatten the whole thing (and ideally remove the abstract base too, unless you have non-templated code that needs it):
template <int PIN, template <int> class BASE>
struct AveragedPin: public BASE<PIN>
{
int read() override { /* call BASE<PIN>::read() several times */ }
int getNo() override { return PIN; }
};
However, note that we could just use the inherited getNo, and then don't really use PIN at all. So instead of declaring an averaged pin instance as AveragedPin<MY_PIN, AnalogInPin> myAveragedPin;, we could change the definition to
template <class BASE>
struct AveragedPin: public BASE
{
int read() override { /* call BASE::read() several times */ }
using BASE::getNo; // not really required unless it is hidden
};
and declare an instance as AveragedPin<AnalogInPin<MY_PIN>> myAveragedPin;.
The range-corrected pin can be similar but with extra template parameters for the flags and min/max bounds, if they're known at compile time.
Similarly, the FixedRangeCorrectPin added to your question, doesn't need to derive from AnalogInPin and then also store a different pin type. In fact, it can just inherit the base class
template <class P,int rawMin,int rawMax,int targetRange>
struct FixedRangeCorrectedPin : public P
{
int read(); // calls P::read()
// inherit getNo again
};
again, declaring an instance like FixedRangeCorrectPin<AnalogInPin<MY_PIN>, RMIN, RMAX, TARGET> myFixedPin;
Edit Example of an average over a variable number of pins, with no storage overhead, assuming we changed the virtual methods to static:
template <class... PINS>
struct AveragedPins
{
static int read()
{
return (PINS::read() + ...) / sizeof...(PINS);
}
};
This doesn't care what sort of pin the argument is, so long as it has a static read method. You can stack it however you like:
using a1 = FixedRangeCorrectedPin<A_1, 0, 255, 128>;
using a2 = AnalogInPin<A_2>;
using a3 = AnalogInPin<A_3>;
using a4 = AnalogInPin<A_4>;
using a34 = AveragedPins<a3, a4>;
using all = AveragedPins<a1, a2, a34>;
// now a34::read() = (a3::read() + a4::read())/2
// and all::read() = (a1::read() + a2::read() + a34::read())/3
and note that all of those are just type definitions: we're not allocating even one byte for any objects.
One more note: I noticed that I'm using the same CLASS::method() syntax in two slightly different ways.
in the first examples above, which use inheritance, BASE::read() is a de-virtualized instance method call.
That is, we're calling BASE's version of the read method on this object. You could also write this->BASE::read().
It's de-virtualized because although the base-class method is virtual, we know at compile time the right override to call, so virtual dispatch isn't necessary.
in the final examples, where we stopped using inheritance and made the methods static, PIN::read() has no this and there is no object at all.
This is the most similar in principle to calling a free C function, although we're getting the compiler to generate a new instance of it for each different PIN value (and then expecting it to inline the call anyway).
I have 2 issues in a template class I'm building. I've included example code below. First question is whether I can coerce the auto type deducted for a templated class. i.e.:
auto p = myvar;
where myvar is T<...>, could I force auto to detect Q<...>? This is simplified. Read on for a more clear explanation.
Edited for clarity: Let me explain what I'm doing. And I'd also like to indicate that this style code is working on a large-scale project perfectly well. I am trying to add some features and functions and in addition to smooth out some of the more awkward behaviors.
The code uses templates to perform work on n-dimensional arrays. The template has a top-level class, and a storage class underneath. Passing the storage class into the top level class allows for a top level class which inherits the storage class. So I start with NDimVar, and I have NDimStor. I end up with
NDimVar<NDimStor>
The class contains NO DATA except for the buffer of data:
class NDimStor<size_t... dimensions> {
int buffer[Size<dimensions...>()]
}
This makes the address of the class == the address of the buffer. This is key to the whole implementation. Is this an incorrect assumption? (I can see this works on my system without any issues, but perhaps this isn't always the case.)
When I create NDimVar<NDimStor<10,10>> I end up with a 10x10 array.
I have functions for getting pieces of the array, for example:
NDimVar<NDimStor<dimensions...>>::RemoveDim & get(int index);
This creates a new 1d array of 10 elements out of the 2d 10x10 array:
NDimVar<NdimStor<10>>
In order to return this as a reference, I use a reinterpret_cast at the location of the data I want. So in this example, get(3) would perform:
return reinterpret_cast<NDimVar≤NDimStor<dimensions...>>::RemoveDim&>(buffer[index * DimensionSumBelow<0>()]);
DimensionSumBelow<0> returns the sum of elements at dimensions 1+, i.e. 10. So &buffer[30] is the address of the referenced 1d NDimVar.
All of this works very well.
The only issue I have is that I would like to add on overlays. For example, be able to return a reference to a new class:
NDimVar<NDimPermute<NDimStor<10,10>,1,0>>
that points to the same original location along with a permutation behavior (swapping dimensions). This also works well. But I would like for:
auto p = myvar.Permute<1,0>()
to create a new copy of myvar with permuted data. This would work if I said:
NDimVar<NDimStor<10,10>> p = myvar.Permute<1,0>().
I feel that there is some auto type deduction stuff I could do in order to coerce the auto type returned, but I'm not sure. I haven't been able to figure it out.
Thanks again,
Nachum
What I want is:
1. Create temporary overlay classes on my storage, e.g. A_top<A_storage> can return a type called A_top<A_overlay<A_storage>> without creating a new object, it just returns a reference to this type. This changes the way the storage is accessed. The problem is upon a call to auto. I don't want this type to be instantiated directly. Can I modify the return to auto to be an original A_top?
#include <iostream>
using namespace std;
class A_storage {
public:
float arr[10];
A_storage () {
}
float & el (int index) {
return arr[index];
}
};
template <typename T> class A_overlay : T {
private:
A_overlay () {
cout << "A_overlay ()" << endl;
}
A_overlay (const A_overlay &) {
cout << "A_overlay (&)" << endl;
}
public:
using T::arr;
float & el (int index) {
return arr[10 - index];
}
};
template <typename T> class A_top;
template <typename T> class A_top : public T {
public:
A_top () {
}
A_top<A_overlay<A_storage>> & get () {
return reinterpret_cast<A_top<A_overlay<A_storage>>&>(*this);
}
};
using A = A_top<A_storage>;
int main (void) {
A a;
auto c = a.get(); // illegal - can i auto type deduce to A_top<A_storage>?
return 0;
}
If a function accepts (A_top<A_storage> &) as a parameter, how can I create a conversion function that can cast A_top<A_overlay<A_storage>>& to A_top<A_storage>& ?
Thanks,
Nachum
First, your design doesn't look right to me, and I'm not sure if the behaviour is actually well-defined or not. (Probably not.)
In any case, the problem is not with auto. The error is caused by the fact that the copy constructor of A_overlay is private, while you need it to copy A_top<A_overlay<A_storage>> returned by a.get() to auto c.
(Note that the auto in this case obviously gets deduced to A_top<A_overlay<A_storage>>, I assume you made a typo when said that it's A_top<A_storage>.)
Also note that A_storage in A_top::get() should be replaced with T, even if it doesn't change anything in your snippet because you only have T == A_storage.
If a function accepts (A_top &) as a parameter, how can I create a conversion function that can cast A_top> to A_top& ?
Ehm, isn't it just this:
return reinterpret_cast<A_top<A_storage>&>(obj);
reinterpret_cast should almost never be used. It essentially remove any compiler validation that the types are related. And doing unrelated cast is essentially undefined behavior as it essentially assume that derived classes are always at offset 0...
It does not make any sense to write such code. It is not maintainable and hard to understand what you are trying to achieve. It look like you want to pretend that your A_top<A_storage> object is a A_top<A_overlay<A_storage>> object instead. If this is what you want to do, then declare A alias as that type.
In your code, it look like you want to invert the indexing so that item at position 10 is returned when you ask item at position 0 and vice versa. Do you really think, that it is obvious from your obfuscated code? Never write such bad code.
Something like
class A_overlay {
public:
float & el (int index) { return arr[10 - index]; }
private:
A_storage arr;
};
would make much more sense than your current code.
No cast needed.
Easy to understand.
Well defined behavior.
You might keep your job.
And obviously, you would update the following line as appropriate:
using A = A_top<A_storage>;
Also, if A_top has no useful purpose, then why not using A_overlay directly? And why are you using template if A_storage is not a template? Do you really want to reuse such mess elsewhere in your code base.
Obviously, your code inheritance does not respect IS-A relationship if your write such code. So it is clearly a bad design!
I have an issue with a small game program I'm trying to write. I created a template class "Board" that holds a 2D array of type "T" so that I can use the board for different types of games. The issue is that the array (T board[SIZE][SIZE]) needs to be modified during the game. Another class "Othello" has a "Board" of type "Tile" which is a struct that contains two variables, "Player" (defined by another class) to state which player is in control of the tile, and two bool variables "black" and "white" to state if either player can move there. So this is basically what it looks like:
Board:
int SIZE = 8;
template<class T>
class Board {
public:
// class functions
private:
T board[SIZE][SIZE]
};
Othello:
class Othello {
public:
// class functions
private:
// function helpers
struct Tile {
Player current; // current tile holder (BLACK, WHITE, NEUTRAL)
bool black; // can black capture?
bool white; // can white capture?
unsigned location; // number of the tile, counted from left to right
};
Board<Tile> othelloBoard; // board for the game
int bCounter; // counter for black units
int wCounter; // counter for white units
User playerOne; // information for first player
User playerTwo; // information for second player
};
The issue is that I can't modify the "Board" directly through the "Othello" class (I can't access the board through the Othello class, so othelloBoard.board[x][y].current = WHITE; for instance doesn't work), but I can't define a modifier function within "Board" since the type can be anything. I can't seem to wrap my head around how I would go about doing this. Maybe I'm missing something really simple. This isn't a school project, I'm revisiting an old project from my first C++ course and trying to rebuild it myself. Thanks for any help!
The question is: what is a Board? And what abstraction does it provide (if any)? You didn't show the class function here so I don't really now. As you seem to try to use it, it seems pretty useless. Anyway with a very shallow encapsulation, you can just provide accessors for Tiles:
template<class T, int SIZE = 8>
class Board {
public:
T &tileAt(int x, int y) {
assert(x>=0 && x < SIZE && y>=0 && y<SIZE);
return board(x, y);
}
// class functions
private:
T board[SIZE][SIZE]
};
(note that I moved the SIZE as a template parameters, so that your future Tic-Tac-Toe game can instantiate another version of the template changing the size)
Is there a way to have a matrix of user-defined type in OpenCV 2.x? Something like :
cv::Mat_<KalmanRGBPixel> backgroundModel;
I know cv::Mat<> is meant for image and mathematic, but I want to hold data in a matrix form. I don't plan to use inverse, transpose, multiplication, etc., it's only to store data. I want it to be in matrix form because the pixel_ij of each frame of a video will be linked to backgroundModel_ij.
I know there is a DataType<_Tp> class in core.hpp that needs to be defined for my type but I'm not sure how to do it.
EDIT : KalmanRGBPixel is only a wrapper for cv::KalmanFilter class. As for now, it's the only member.
... some functions ...
private:
cv::KalmanFilter kalman;
Thanks for your help.
I have a more long winded answer for anybody wanting to create a matrix of custom objects, of whatever size.
You will need to specialize the DataType template but instead of having 1 channel, you make the channels the same size of your custom object. You may also need to override a few functions to get expected functionality, but back to that later.
First, here is an example of my custom type template specialization:
typedef HOGFilter::Sample Sample;
namespace cv {
template<> class DataType<Sample>
{
public:
typedef HOGFilter::Sample value_type;
typedef HOGFilter::Sample channel_type;
typedef HOGFilter::Sample work_type;
typedef HOGFilter::Sample vec_type;
enum {
depth = CV_8U,
channels = sizeof(HOGFilter::Sample),
type = CV_MAKETYPE(depth, channels),
};
};
}
Second.. you may want to override some functions to get expected functionality:
// Special version of Mat, a matrix of Samples. Using the power of opencvs
// matrix manipulation and multi-threading capabilities
class SampleMat : public cv::Mat_<Sample>
{
typedef cv::Mat_<Sample> super;
public:
SampleMat(int width = 0, int height = 0);
SampleMat &operator=(const SampleMat &mat);
const Sample& at(int x, int y = 0);
};
The typedef of super isnt required but helps with readability in the cpp.
Notice I have overriden the constructor with width/hight parameters. This is because we have to instantiate the mat this way if we want a 2D matrix.
SampleMat::SampleMat(int width, int height)
{
int count = width * height;
for (int i = 0; i < count; ++i)
{
HOGFilter::Sample sample;
this->push_back(sample);
}
*dynamic_cast<Mat_*>(this) = super::reshape(channels(), height);
}
The at<_T>() override is just for cleaner code:
const Sample & SampleMat::at(int x, int y)
{
if (y == 0)
return super::at<Sample>(x);
return super::at<Sample>(cv::Point(x, y));
}
In the OpenCV documentation it is explained how to add custom types to OpenCV matrices. You need to define the corresponding cv::DataType.
https://docs.opencv.org/master/d0/d3a/classcv_1_1DataType.html
The DataType class is basically used to provide a description of such primitive data types without adding any fields or methods to the corresponding classes (and it is actually impossible to add anything to primitive C/C++ data types). This technique is known in C++ as class traits. It is not DataType itself that is used but its specialized versions […] The main purpose of this class is to convert compilation-time type information to an OpenCV-compatible data type identifier […]
(Yes, finally I answer the question itself in this thread!)
If you don't want to use the OpenCV functionality, then Mat is not the right type for you.
Use std::vector<std::vector<Type> > instead. You can give the size during initialization:
std::vector<std::vector<Type> > matrix(42, std::vector<Type>(23));
Then you can access with []-operator. No need to screw around with obscure cv::Mats here.
If you would really need to go for an OpenCV-Matrix, you are right in that you have to define the DataType. It is basically a bunch of traits. You can read about C++ Traits on the web.
You can create a CV mat that users your own allocated memory by specifying the address to the constructor. If you also want the width and height to be correct you will need to find an openCV pixel type that is the same number of bytes.