我尝试使用g ++ 4.8.2(Ubuntu 14.04环境)编译C ++脉冲国际象棋引擎[0]。
我在链接阶段遇到以下错误:
Linking CXX executable pulse-
CMakeFiles/pulse.dir/main.cpp.o: In function `pulse::MoveGenerator::MoveGenerator()':
/home/user/cpp/movegenerator.h:15: undefined reference to `pulse::MoveList<pulse::MoveEntry>::MoveList()'
libcore.so: undefined reference to `pulse::MoveList<pulse::MoveEntry>::rateFromMVVLVA()'
libcore.so: undefined reference to `pulse::MoveList<pulse::RootEntry>::sort()'
libcore.so: undefined reference to `pulse::MoveList<pulse::RootEntry>::MoveList()'
libcore.so: undefined reference to `pulse::MoveList<pulse::MoveEntry>::sort()'
collect2: error: ld returned 1 exit status
当我运行命令时:
g++ -std=c++11 -c movelist.cpp && nm movelist.o | grep sort
我得到了输出
0000000000000000 W _ZN5pulse8MoveListINS_9MoveEntryEE4sortEv
0000000000000000 W _ZN5pulse8MoveListINS_9RootEntryEE4sortEv
使用4.9.1时,但使用4.8.2时无输出。
为什么g ++ 4.9.1生成排序函数而4.8.2不生成排序函数,它是编译器或脉冲源代码中的错误吗?
修改
正如指出的重复问题&#34;为什么模板只能在头文件中实现?&#34;,我还没有得到它,它是如何在g ++ 4.9.1中工作的? movelist标题:
#include "value.h"
#include "move.h"
#include <array>
#include <memory>
namespace pulse {
/**
* This class stores our moves for a specific position. For the root node we
* will populate pv for every root move.
*/
template<class T>
class MoveList {
private:
static const int MAX_MOVES = 256;
public:
std::array<std::shared_ptr<T>, MAX_MOVES> entries;
int size = 0;
MoveList();
void sort();
void rateFromMVVLVA();
};
class MoveVariation {
public:
std::array<int, Depth::MAX_PLY> moves;
int size = 0;
};
class MoveEntry {
public:
int move = Move::NOMOVE;
int value = Value::NOVALUE;
};
class RootEntry : public MoveEntry {
public:
MoveVariation pv;
};
}
movelist来源:
#include "movelist.h"
#include <cassert>
namespace pulse {
template class MoveList<MoveEntry>;
template class MoveList<RootEntry>;
template<class T>
MoveList<T>::MoveList() {
for (unsigned int i = 0; i < entries.size(); ++i) {
entries[i] = std::shared_ptr<T>(new T());
}
}
/**
* Sorts the move list using a stable insertion sort.
*/
template<class T>
void MoveList<T>::sort() {
for (int i = 1; i < size; ++i) {
std::shared_ptr<T> entry(entries[i]);
int j = i;
while ((j > 0) && (entries[j - 1]->value < entry->value)) {
entries[j] = entries[j - 1];
--j;
}
entries[j] = entry;
}
}
/**
* Rates the moves in the list according to "Most Valuable Victim - Least Valuable Aggressor".
*/
template<class T>
void MoveList<T>::rateFromMVVLVA() {
for (int i = 0; i < size; ++i) {
int move = entries[i]->move;
int value = 0;
int piecetypeValue = PieceType::getValue(Piece::getType(Move::getOriginPiece(move)));
value += PieceType::KING_VALUE / piecetypeValue;
int target = Move::getTargetPiece(move);
if (Piece::isValid(target)) {
value += 10 * PieceType::getValue(Piece::getType(target));
}
assert(value >= (PieceType::KING_VALUE / PieceType::KING_VALUE)
&& value <= (PieceType::KING_VALUE / PieceType::PAWN_VALUE) + 10 * PieceType::QUEEN_VALUE);
entries[i]->value = value;
}
}
[0] https://github.com/fluxroot/pulse/tree/master/src/main/cpp
答案 0 :(得分:2)
将以模板类开头的两行移动到源文件的末尾。
此源使用显式模板实例化(14.7.2)。只要在整个程序中只使用模板的显式实例化,就可以在源文件中定义模板(而不是在头文件中)。在这种情况下,这些将是MoveList<MoveEntry>
和MoveList<RootEntry>
。
但是,有一个问题:显式专业化必须在模板定义之后出现(14.7.2 / 4)
类模板的函数模板,变量模板,成员函数或静态数据成员的声明,或类或类模板的成员函数模板应在该实体的显式实例化之前。类模板的定义,类模板的成员类或类或类模板的成员类模板应在该实体的显式实例化之前,除非显式实例化之前具有相同实体的显式特化模板参数。
为什么g ++ 4.9不强制执行此操作是任何人的猜测。