When trying to compile the files bellow this error occurs:
The error
Logging.h: In instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]':
Logging.h:10:64:   required from here
Logging.h:10:64: error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]' but no definition available [-fpermissive]
     template void printBoardWithCandidates<3>(const Board<3>& b);
                                                                ^
As I am not very experienced in C++ I don't see any possible cause for this problem. Since the definition is present in .cpp file I dont see any reason not to compile. Wouldn't someone mind explaing that to me, please?
.h file
#pragma once
#include "Board.h"
namespace Sudoku
{
    template<int BASE>
    void printBoardWithCandidates(const Board<BASE> &b);
    template void printBoardWithCandidates<2>(const Board<2>&);
    template void printBoardWithCandidates<3>(const Board<3>&);
    template void printBoardWithCandidates<4>(const Board<4>&);
} 
.cpp file
#include "Logging.h"
#include <iostream>
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
    // definition...
}
Edit: Similar implementatiin I have employed several times throughout the program. For example Board.h
#pragma once
#include <vector>
#include <cstring>
#include "stdint.h"
namespace Sudoku
{
    struct Cell
    {
        int RowInd;
        int ColInd;
        int BoxInd;
        friend bool operator==(const Cell& cell1, const Cell& cell2);
    };
    
    bool operator==(const Cell& cell1, const Cell& cell2);
    template<int BASE>
    class Board
    {
        public:
            static constexpr int WIDTH = BASE * BASE;
            static constexpr int CELL_COUNT = WIDTH * WIDTH;
            static constexpr uint16_t CELL_COMPLETELY_OCCUPIED = 65535 >> (sizeof(uint16_t) * 8 - WIDTH);
        private:   
            const int EMPTY_VALUE;
            
            uint16_t rowOccupants[WIDTH] = {0};
            uint16_t colOccupants[WIDTH] = {0};
            uint16_t boxOccupants[WIDTH] = {0};
            int* solution;
            void Init();
            void Eliminate(Cell& cell, uint16_t value);
        public:
            std::vector<Cell> EmptyCells;
            Board(const int* puzzle, int* solution, int emptyValue = -1);
            void SetValue(Cell cell, uint16_t value);
            void SetValue(Cell cell, int value);
            int* GetSolution() const; 
            inline uint16_t GetOccupants(Cell cell) const
            {
                return rowOccupants[cell.RowInd] | colOccupants[cell.ColInd] | boxOccupants[cell.BoxInd];
            }
    };
    template class Board<2>;
    template class Board<3>;
    template class Board<4>;
} // namespace Sudoku
 
    