C++ 模板函数的显式实例化导致错误 "no definition available"
C++ Explicit instantiation of a template function results in an error "no definition available"
尝试编译以下文件时出现此错误:
错误
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);
^
由于我对 C++ 的经验不是很丰富,所以我看不出有任何可能导致此问题的原因。由于定义存在于 .cpp 文件中,我看不出有任何理由不编译。有人不介意给我解释一下吗?
.h 文件
#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 文件
#include "Logging.h"
#include <iostream>
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
// definition...
}
编辑:
我在整个程序中多次使用了类似的实现。例如
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
问题 是在 header 文件中您提供 3
显式模板实例化的地方,对应的成员函数模板printBoardWithCandidates
的定义不可用。因此,编译器无法为这些实例生成定义,并给出上述错误:
error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]'
but no definition available [-fpermissive]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
有两种方法可以解决这个问题,如下所示。另请注意,我使用了一个空结构 Board
,因为您提供的 Board
class 非常大(长度),如果粘贴到此处会占用很多 space 2次。不过概念是一样的。
方法一
在header中提供成员函数模板printBoardWithCandidates
的定义,然后提供3个显式模板实例化,如下所示:
header.h
#pragma once
#include "Board.h"
namespace Sudoku
{
template<int BASE>
void printBoardWithCandidates(const Board<BASE> &b)
{
//note this is a definition
}
//explicit template instantiation declaration
extern template void printBoardWithCandidates<2>(const Board<2>&);
extern template void printBoardWithCandidates<3>(const Board<3>&);
extern template void printBoardWithCandidates<4>(const Board<4>&);
}
Board.h
#pragma once
template<int>
struct Board
{
};
main.cpp
#include <iostream>
#include "header.h"
//explicit template instantiation 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>&);
int main()
{
return 0;
}
方法二
这里我们提供了成员函数模板的定义以及源文件中的3个显式模板实例化。在header文件中我们只提供了成员函数模板的声明,在header文件中没有提供显式的模板实例化。
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;
}
尝试编译以下文件时出现此错误:
错误
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);
^
由于我对 C++ 的经验不是很丰富,所以我看不出有任何可能导致此问题的原因。由于定义存在于 .cpp 文件中,我看不出有任何理由不编译。有人不介意给我解释一下吗?
.h 文件
#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 文件
#include "Logging.h"
#include <iostream>
template<int BASE>
void Sudoku::printBoardWithCandidates(const Board<BASE> &board)
{
// definition...
}
编辑: 我在整个程序中多次使用了类似的实现。例如 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
问题 是在 header 文件中您提供 3
显式模板实例化的地方,对应的成员函数模板printBoardWithCandidates
的定义不可用。因此,编译器无法为这些实例生成定义,并给出上述错误:
error: explicit instantiation of 'void Sudoku::printBoardWithCandidates(const Sudoku::Board<BASE>&) [with int BASE = 3]'
but no definition available [-fpermissive]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
有两种方法可以解决这个问题,如下所示。另请注意,我使用了一个空结构 Board
,因为您提供的 Board
class 非常大(长度),如果粘贴到此处会占用很多 space 2次。不过概念是一样的。
方法一
在header中提供成员函数模板printBoardWithCandidates
的定义,然后提供3个显式模板实例化,如下所示:
header.h
#pragma once
#include "Board.h"
namespace Sudoku
{
template<int BASE>
void printBoardWithCandidates(const Board<BASE> &b)
{
//note this is a definition
}
//explicit template instantiation declaration
extern template void printBoardWithCandidates<2>(const Board<2>&);
extern template void printBoardWithCandidates<3>(const Board<3>&);
extern template void printBoardWithCandidates<4>(const Board<4>&);
}
Board.h
#pragma once
template<int>
struct Board
{
};
main.cpp
#include <iostream>
#include "header.h"
//explicit template instantiation 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>&);
int main()
{
return 0;
}
方法二
这里我们提供了成员函数模板的定义以及源文件中的3个显式模板实例化。在header文件中我们只提供了成员函数模板的声明,在header文件中没有提供显式的模板实例化。
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;
}