I have a small collection of algorithms in Java for playing multiple turn-based games, such as TicTacToe, Othello, Checkers, etc. I do it using Java Generics (self-bounded types) to be able to use the same algorithms without having to change them specifically for each game. The reason why I use self-bounded types is not shown here, but is is needed for the Evaluation Functions.
public interface Game<GAME extends Game<GAME>> {
GAME copy();
int getCurPlayer();
...
}
public class TicTacToe implements Game<TicTacToe> {
...
@Override
public TicTacToe copy() {
...
}
@Override
public int getCurPlayer() {
...
}
...
}
Today, just for learning, I tried to move my Java code to C++, using C++ templates.
This was my approach, and obviously it didn’t work.
Game.h
template <typename T>
class Game
{
public:
virtual T copy() const = 0;
virtual int cur_player() const = 0;
...
};
TicTacToe.h
class TicTacToe : public Game<TicTacToe>
{
public:
virtual TicTacToe copy() const;
virtual int cur_player() const;
...
};
TicTacToe.cpp
TicTacToe TicTacToe::copy() {
...
}
int TicTacToe::cur_player() {
...
}
When I try to compile, the errors I get are:
out-of-line definition of 'copy' does not match any declaration in 'TicTacToe'
out-of-line definition of 'cur_player' does not match any declaration in 'TicTacToe'
…
and the same for each of the other pure virtual functions.
Your definitions need to have
constapplied to them as well. The CRTP, as it’s known in C++ (Curiously Recurring Template Pattern) is perfectly valid C++.However, there’s no need for
virtualhere, the CRTP is used to statically dispatch functions and automatically implement functionality.Note that in this case, the derived class does not need to implement a “copy” function, as the copy constructor will automatically be called by “copy”. However, in the general case, as templates are duck typed, it’s unnecessary to do this kind of thing, and normally you’d just use a standard template. Unlike Java’s Generics, C++’s templates have no relation to inheritance at all- the types you can instantiate with do not have to inherit from a common interface.