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
CodePudding user response:
The problem is that at the point inside the header file where you have provided the 3
explicit template instantiation, the definition of the corresponding member function template printBoardWithCandidates
is not available. Thus, the compiler cannot generate the definition for these instantiations and gives the mentioned error saying:
error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]'
but no definition available [-fpermissive]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are two ways to solve this as shown below. Note also that i have used an empty struct Board
since the Board
class you provided is very big(in length) and will take a lot of space if pasted here 2 times. The concept is the same though.
Method 1
Provide the definition for the member function template printBoardWithCandidates
in the header before providing the 3 explicit template instantiations as shown below:
header.h
#pragma once
#include "Board.h"
namespace Sudoku
{
//note this is a definition
template<int BASE>
void printBoardWithCandidates(const Board<BASE> &b)
{
}
//this will work now because the compiler have the definition available above
template void printBoardWithCandidates<2>(const Board<2>&);
template void printBoardWithCandidates<3>(const Board<3>&);
template void printBoardWithCandidates<4>(const Board<4>&);
}
Board.h
#pragma once
template<int>
struct Board
{
};
main.cpp
#include <iostream>
#include "header.h"
int main()
{
return 0;
}
Method 2
Here we provide the definition of the member function template as well as the 3 explicit template instantiations in the source file. In the header file we only provide the declaration for the member function template and no explicit template instantiation are provided in the header file.
header.h
#pragma once
#include "Board.h"
namespace Sudoku
{
//this is a declaration not a definition
template<int BASE>
void printBoardWithCandidates(const Board<BASE> &b);
//no explicit template instantiation here since we have provided only the declaration above and not the definition
}
Board.h
#pragma once
template<int>
struct Board
{
};
source.cpp
#include "header.h"
//provide the definition here
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
// definition...
}
template void Sudoku::printBoardWithCandidates<2>(const Board<2>&);
template void Sudoku::printBoardWithCandidates<3>(const Board<3>&);
template void Sudoku::printBoardWithCandidates<4>(const Board<4>&);
main.cpp
#include <iostream>
#include "header.h"
int main()
{
return 0;
}