views:

43

answers:

1

I'm having trouble passing a callback function from within a class, when calling a template function. Here's a sample code:

sortedlist.h

#ifndef _sortedlist_h
#define _sortedlist_h

#include <vector>    

template <typename ElemType>
class SortedList {
public:
    SortedList(int (*compare)(ElemType a, ElemType b));
    ~SortedList();

    void push(ElemType newElem);
    ElemType pop();

private:
    std::vector<ElemType> v;
    int (*cmp) (ElemType first, ElemType second);
    void Sort();
};


template <typename ElemType>
SortedList<ElemType>::SortedList(int (*compare)(ElemType a, ElemType b)) {
    cmp = compare;
}

template <typename ElemType>
SortedList<ElemType>::~SortedList() {
}

template <typename ElemType>
void SortedList<ElemType>::push(ElemType newElem) {
    v.push_back(newElem);
    Sort();
}

template <typename ElemType>
ElemType SortedList<ElemType>::pop() {
    ElemType next = v.back();
    v.pop_back();
    return next;
}

template <typename ElemType>
void SortedList<ElemType>::Sort() {
    for (int i=v.size()-1; i>0; i--) {
        if(cmp(v[i], v[i-1]) < 0) {  //compare function
            ElemType temp = v[i];
            v[i] = v[i-1];
            v[i-1] = temp;
        }
        else return;
    }
}

#endif

game.h

#ifndef _game_h
#define _game_h

#include <string>
#include "sortedlist.h"

class Game {
public:
    Game() {};
    ~Game() {};
    void addPlayer(std::string name, int score);
    std::string getWinner();

    struct Player {
        std::string name;
        int score;
    };

    //compare function
    int highScore(Player one, Player two);

private:    
    SortedList<Player> list(highScore);

};

#endif

game.cpp

#include "game.h"

void Game::addPlayer(std::string name, int score) {
    Player newEntry;
    newEntry.name = name;
    newEntry.score = score;
    list.push(newEntry);    
}

std::string Game::getWinner() {
    return list.pop().name;
}

//compare funtion
int Game::highScore(Player one, Player two) {
    if (one.score == two.score) return 0;
    if (one.score > two.score) return 1;
    return -1;
}

sample main:

#include <iostream>
#include "game.h"
using namespace std;

int main () {
    Game pacman;
    pacman.addPlayer("Beavis", 100);
    pacman.addPlayer("Butthead", 200);
    cout << pacman.getWinner() << endl; 
}

When I compile it on XCode, I get "'highscore' is not a type" error. I also tried moving Player and highScore outside of the class with similar results. What should I do instead?

+3  A: 

In C++ you cannot initialize class-members in-place. You need to do that in the constructor initializer list

class Game {
public:
    Game():list(highScore) {};
    ~Game() {};

    //compare function
    static int highScore(Player one, Player two);

private:    
    SortedList<Player> list;
};

The function needs to be declared as static in the class definition as SortedList calls it without a *this pointer, like an ordinary function.

Performance is really unnecessary bad of the comparison function because you always copy the two items to be compared when passing them as arguments. Better make the comparison function's type to receive const-references and change highScore's signature appropriately

int (*compare)(ElemType const& a, ElemType const& b);
Johannes Schaub - litb
Luciano
@Luciano: That would suggest that you forgot to make the change somewhere (the `highScore` function doesn't take references?). In C++, it would probably be more common to use `std::sort` or `std::stable_sort`, and use predicates that determine "less-than" relationship (`bool compare_scores(const Player}`) - in some cases it might even make sense to overload `operator<`.
UncleBens
Luciano
What if list is not a member, rather is initialized inside a member function. Example: static int TopScore() { SortedList<Player> topten() ...I can't use the constructor, because topten is not a member.
Luciano