This problem took me hours, and yet I don't understand a bit what I did wrong.
This is the compilation error message:
Error 113 error C2298: 'return' : illegal operation on pointer to member function expression c:\program files\wt 3.3.2 msvs2012 x86\include\boost\bind\mem_fn.hpp 342 1 Monopoly
The error is located in mem_fn.hpp, in the function dm::operator()
. I pastebin'd the file here (Line 342).
I am guessing the problem stems from boost::bind()
, but I checked the functions I binded and they all seem to have the right number of arguments.
#include <Wt/WApplication>
#include <Wt/WPushButton>
#include <Wt/WTable>
#include <Wt/WEnvironment>
#include <Wt/WServer>
#include <vector>
using namespace Wt;
using std::vector;
using std::string;
enum Tile {
N, X, O
};
class TicTacToeGame;
class TicTacToeClient: public WApplication {
public:
TicTacToeClient(const WEnvironment& env);
void connectFrom(TicTacToeGame& game);
void setTile(Tile t);
void updateBoard(int, int, Tile);
private:
void takeMove(int i, int j);
Tile tile;
Signal<int, int, Tile>* moveTaken;
WTable* table;
};
class TicTacToeGame {
public:
static vector<TicTacToeGame*> games;
TicTacToeGame(TicTacToeClient* x): playerX(x) {
for(int i=0;i<3;i++){
vector<Tile> line;
for(int j=0;j<3;j++)
line.push_back(Tile::N);
grid.push_back(line);
}
playerX->connectFrom(*this);
playerX->setTile(Tile::X);
playerX->enableUpdates();
}
void updateBoard(int x, int y, Tile t){
playerX->environment().server()->post(playerX->sessionId(), boost::bind(&TicTacToeClient::updateBoard, playerX, x, y, t));
playerO->environment().server()->post(playerO->sessionId(), boost::bind(&TicTacToeClient::updateBoard, playerO, x, y, t));
}
void join(TicTacToeClient* o){
playerO = o;
playerO->connectFrom(*this);
playerO->setTile(Tile::O);
playerO->enableUpdates();
}
private:
vector<vector<Tile>> grid;
TicTacToeClient* playerX;
TicTacToeClient* playerO;
};
vector<TicTacToeGame*> TicTacToeGame::games = vector<TicTacToeGame*>();
TicTacToeClient::TicTacToeClient(const WEnvironment& env): WApplication(env), moveTaken(new Signal<int, int, Tile>){
WTable* table = new WTable();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
WPushButton* button = new WPushButton();
button->setWidth(50);
button->setHeight(50);
button->clicked().connect(boost::bind(&TicTacToeClient::takeMove, this, i, j));
WTableCell* cell = table->elementAt(i,j);
cell->addWidget(button);
cell->setHeight(50);
cell->setWidth(50);
}
}
root()->addWidget(table);
this->table = table;
}
void TicTacToeClient::connectFrom(TicTacToeGame& game){
moveTaken->connect(boost::bind(&TicTacToeGame::updateBoard, &game));
}
void TicTacToeClient::setTile(Tile t){tile = t;}
void TicTacToeClient::updateBoard(int x, int y, Tile t){
WTableCell* cell = table->elementAt(x, y);
cell->clear();
string text;
switch(t){
case Tile::X:
text = "X";
break;
case Tile::O:
text = "O";
break;
}
cell->addWidget(new WText(text));
}
void TicTacToeClient::takeMove(int i, int j){
moveTaken->emit(i, j, tile);
}
WApplication *createApplication(const WEnvironment& env)
{
TicTacToeClient* client = new TicTacToeClient(env);
if(TicTacToeGame::games.empty())
TicTacToeGame::games.push_back(new TicTacToeGame(client));
else
TicTacToeGame::games[0]->join(client);
return client;
}
int main(int argc, char **argv)
{
return WRun(argc, argv, &createApplication);
}
I am using 32-bit Win7, MSVS Express 2012, Wt is 3.3.2, installed by "the easy method" here.
I think your problem stems from this:
void TicTacToeClient::connectFrom(TicTacToeGame& game){
moveTaken->connect(boost::bind(&TicTacToeGame::updateBoard, &game));
}
You bind the invoking object (&game), but the function takes 3 arguments. I'm not familiar with Wt, but it looks like the moveTaken Signal will call the function with the proper arguments. In that case you just need to add placeholders to your boost::bind call.
moveTaken->connect(boost::bind(&TicTacToeGame::updateBoard, &game, _1, _2, _3));
I'm not certain about this though so let me know how it turns out.