0

I have a class that for simplicity we call Cell, it has 3 variables:

  • mark
  • colorMark
  • backgroundColor

a constructor and a function

Cell.h:

#pragma once
#include "macro.h"

using namespace std;

class Cell    
{
    public:
    Cell(char mark, int markColor, int backgroundColor);
    void set_value(int parameter, auto value);
    int x, y, markColor, backgroundColor;
    char mark;
};

Cell.cpp:

Cell::Cell(char mark, int markColor, int backgroundColor)
{
    Cell::x = -1;
    Cell::y = -1;
    Cell::mark = mark;
    Cell::markColor = markColor;
    Cell::backgroundColor = backgroundColor;
}

void Cell::set_value(int parameter, auto value)
{
    switch (parameter)
    {
        case PARAMETER_MARK:
            Cell::mark = value;
            break;
        
        case PARAMETER_MARK_COLOR:
            Cell::markColor = value;
            break;
        
        case PARAMETER_BK_COLOR:
            Cell::backgroundColor = value;
            break;
    }
}

And then I have a class called Painter that deals with manipulating the parameters of a cell vector through transformations.

Painter.h:

#pragma once
#include <vector>
#include <stdio.h>
#include <ctime>
#include "Cell.h"

using namespace std;

typedef vector <Cell> element_cells;

using namespace std;

class Painter
{
    public:
        Painter(element_cells* cells);
        Painter();

        void set_cells(element_cells* cells);
        void paint(int parameter, int paintType, auto value);

        element_cells* cells;
        size_t numberCells;
};

The most important function of Painter is paint(...), it takes two integers one to specify the cell parameter to be modified and the other to specify the type of transformation to be applied to the cell vector, the last parameter is a value needed for almost all types of transformation, as in these transformations the value type is not constant I need a auto type.

To specify the cell parameter and the type of transformation I use macros

Painter.cpp

...
void Painter::paint(int parameter, int paintType, auto value)
{
    int i;
    switch (paintType)
    {
        case PAINT_TYPE_SINGLE:
        {
            for (i = 0; i < Painter::numberCells; i++)
            {
                Painter::cells->at(i).set_value(parameter, value);
            }
            break;
        }

        case PAINT_TYPE_SCALAR:
        {
            int j = 0;
            for (int i = 0; i < Painter::numberCells; i++)
            {
                Painter::cells->at(i).set_value(parameter, value.at(j));
                j = (j < (value.size() - 1)) ? j += 1 : j = 0;
            }

            break;
        }

        case PAINT_TYPE_RANDOM:
        {
            int casualNum;
            srand(time(NULL));
            for (int i = 0; i < Painter::numberCells; i++)
            {
                if (parameter == PARAMETER_MARK)
                    do { casualNum = rand() % 256; } while ((casualNum < 32) || (casualNum == 127));
                else
                    casualNum = rand() % 16;

                Painter::cells->at(i).set_value(parameter, value);
            }
            break;
        }

        case PAINT_TYPE_RANDOM_BETWEEN:
        {
            int casualNum;
            srand(time(NULL));

            for (int i = 0; i < Painter::numberCells; i++)
            {
                casualNum = rand() % value.size();
                Painter::cells->at(i).set_value(parameter, value.at(casualNum));
            }
            break;
        }
    }
}

But when I execute this code:

#include <iostream>
#include "Painter.h"

using namespace std;

int main()
{
    element_cells cells;
    Cell defaultCell;

    int i;

    for (i = 0; i < 10; i++)
    {
        cells.push_back(defaultCell);
    }

    Painter p(&cells);
    p.paint(PARAMETER_MARK, PAINT_TYPE_SINGLE, 'A');

    for (i = 0; i < cells.size(); i++)
    {
        cout << "Cell " << i << "*) " << "| x: " << cells.at(i).x << " | y: " << cells.at(i).y << " | mark: " << cells.at(i).mark << " | colorMark: " << cells.at(i).markColor << " | Background Color: " << cells.at(i).backgroundColor << endl;
    }

    return 0;
}

The compiler returns the following error:

`Severity Code Description Project File Line Deletion Status Error LNK2019 reference to the external symbol "public: void __cdecl Painter::paint<char>(int,int, char)" (??$paint@D@Painter@@QEAAXHHD@Z) not resolved in the main function AreaTest C:\Users\albya\Personal\Programming\C++\Software Challenge - 2022\AreaTest\AreaTest\AreaTest.obj 1`

`Severity Code Description Project File Line Deletion Status Error LNK1120 1 external unresolved AreaTest C:\Users\albya\Personal\Programming\C++\Software Challenge - 2022\AreaTest\x64\Debug\AreaTest.exe 1`

the same thing happens when I use templates and any (for cell):

Cell.h:

...
void set_value(int parameter, any value);
...

Cell.cpp:

...
void Cell::set_value(int parameter, any value)
{
    switch (parameter)
    {
        case PARAMETER_MARK:
            Cell::mark = any_cast<char>(value);
            break;

        case PARAMETER_MARK_COLOR:
            Cell::markColor = any_cast<int>(value);
            break;

        case PARAMETER_BK_COLOR:
            Cell::backgroundColor = any_cast<int>(value);
            break;
    }
}
...

Painter.h:

#pragma once

#include <vector>

#include <stdio.h>
#include <ctime>

#include "Cell.h"

using namespace std;

typedef vector <Cell> element_cells;

using namespace std;

class Painter
{
    public:
        Painter(element_cells* cells);
        Painter();

        void set_cells(element_cells* cells);

        template <typename tmpType>
        void paint(int parameter, int paintType, tmpType value);
        
        element_cells* cells;
        size_t numberCells;
};

Painter.cpp:

...

template <typename tmpType>
void Painter::paint(int parameter, int paintType, tmpType value)
{
    int i;
    
    switch (paintType)
    {
        case PAINT_TYPE_SINGLE:
        {
            for (i = 0; i < Painter::numberCells; i++)
            {
                Painter::cells->at(i).set_value(parameter, value);
            }

            break;
        }

        case PAINT_TYPE_SCALAR:
        {
            int j = 0;
            for (int i = 0; i < Painter::numberCells; i++)
            {
                Painter::cells->at(i).set_value(parameter, value.at(j));
                j = (j < (value.size() - 1)) ? j += 1 : j = 0;
            }

            break;
        }

        case PAINT_TYPE_RANDOM:
        {
            int casualNum;

            srand(time(NULL));
            for (int i = 0; i < Painter::numberCells; i++)
            {
                if (parameter == PARAMETER_MARK)
                    do { casualNum = rand() % 256; } while ((casualNum < 32) || (casualNum == 127));
                else
                    casualNum = rand() % 16;

                Painter::cells->at(i).set_value(parameter, value);
            }

            break;
        }
        
        case PAINT_TYPE_RANDOM_BETWEEN:
        {
            int casualNum;

            srand(time(NULL));
            for (int i = 0; i < Painter::numberCells; i++)
            {
                casualNum = rand() % value.size();
                Painter::cells->at(i).set_value(parameter, value.at(casualNum));
            }

            break;
        }
    }
}

Main:

#include <iostream>
#include "Painter.h"

using namespace std;

int main()
{
    element_cells cells;
    Cell defaultCell;

    int i;

    for (i = 0; i < 10; i++)
    {
        cells.push_back(defaultCell);
    }

    Painter p(&cells);

    p.paint<char>(PARAMETER_MARK, PAINT_TYPE_SINGLE, 'A');

    for (i = 0; i < cells.size(); i++)
    {
        cout << "Cell " << i << "*) " << "| x: " << cells.at(i).x << " | y: " << cells.at(i).y << " | mark: " << cells.at(i).mark << " | colorMark: " << cells.at(i).markColor << " | Background Color: " << cells.at(i).backgroundColor << endl;
    }
    return 0;
}

The compiler returns the following error:

Severity Code Description Project File Line Deletion Status Error LNK2019 reference to the external symbol "public: void __cdecl Painter::paint<char>(int,int,char)" (??$paint@D@Painter@@QEAAXHHD@Z) not resolved in the main function AreaTest C:\Users\albya\Personal\Programming\C++\Software Challenge - 2022\AreaTest\AreaTest\AreaTest.obj 1


Severity Code Description Project File Line Deletion Status Error LNK1120 1 external unresolved AreaTest C:\Users\albya\Personal\Programming\C++\Software Challenge - 2022\AreaTest\x64\Debug\AreaTest.exe 1

As I understand it, the error, in both ways, with auto and with templates, lies in the fact that it does not see the definition of functions with auto/template.

If the error is this, I don't know how to fix it, could someone tell me how,

thanks in advance

Titan
  • 99
  • 7
  • 2
    Does this answer your question? [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – tkausl Jul 05 '22 at 09:02
  • In `Cell` don't name the constructor arguments like member variables, use a member initializer list. If you reorder it so `x` and `y` are at the end you can use aggregate initializaion and don't need a constructor at all. Using `auto` in `set_value` makes it a template function. But a really bad one. The type should depend on the `parameter`, which really should not be an `int`. Why not replace `parameter` with a member pointer? Then you can match the type of the pointer with the type of the value? That also removes the need to `switch`. Actually you don't need the `set_value` function at all – Goswin von Brederlow Jul 05 '22 at 09:36
  • @Goswin von Brederlow, Do you think my code is wrong?, I did it because I previously had 4 functions repeating for each cell parameter (3), for a total of 12 functions. I therefore wanted to group and compact the code. What do you think? – Titan Jul 05 '22 at 09:56
  • As said I would just use a member pointer to pick the value and the whole question goes away. – Goswin von Brederlow Jul 05 '22 at 10:13

0 Answers0