Class member calls function template with callback function - c++

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 function
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?

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);

Related

How to pass functions as parameters within a class?

I am trying to pass my print function as a paramater through my inordertraversal class which belongs to a templated binarySearchTree. whenever I define these functions within main the program works fine but whenever i try to encapsulate them I get a error:
"expected primary-expression before '&' token"
This is the code that works
void print(classdatatype& x);
int main()
{
binarySearchTree<classdatatype> tree;
tree.inorderTraversal(print);
return 0;
}
void print(classdatatype& x) { cout << x << " "; }
The declaration of my inordertraveral templated class is
template <class elemType>
void binarySearchTree<elemType>::inorderTraversal(void (*visit)(elemType& item))
I can show the rest of the code if needed but this all works just fine
Once I move these functions into my class it looks like this
(the declarations for print and the binarySearchTree are in the .cpp same as they are declared above)
void bst::printfunctions(classdatatype& x)
{
tree.inorderTraversal(print(classdatatype & x)); //error here
}
void bst::print(classdatatype& x)
{
cout << x << " ";
}
The error is to do within the brackets of print, I have tried many different things but to me this is the correct declaration; therefore I don't know why it's not working.
Any advice would be greatly appreciated.
EDIT: print is a function pointer to print the details of classdatatype which is stored inside a binary search tree.
EDIT2: minimal reproducible example.
Data types are as they are and not like in the above example. This is as basic as I could make this and I ended up getting another error which I couldn't resolve but for the purpose of this example it doesn't matter and should be ignored.
main() is included but is minimal and may not serve its purpose but the problem doesn't lie here anyway.
main()
#include <iostream>
#include "windlogtype.h"
using namespace std;
int main()
{
windlogtype wind;
ifstream infile("data.txt");
//for purose of this data is one integer value
infile >> wind;
//do something
//main purpose is to get input
return 0;
}
class windlogtype
#include "windlogtype.h"
windlogtype::windlogtype() { }
windlogtype::windlogtype(int i) { num = i; }
int windlogtype::Getnumber() const { return num; }
void windlogtype::Setnumber(int i) { num = i; }
ostream operator<<(ostream& os, const windlogtype& w)
{
os << w.Getnumber() << '\n';
return os;
}
#ifndef WINDLOGTYPE_H
#define WINDLOGTYPE_H
#include <iostream>
using namespace std;
class windlogtype
{
public:
windlogtype();
windlogtype(int i);
int Getnumber() const;
void Setnumber(int i);
private:
int num;
};
ostream operator<<(ostream& os, const windlogtype& w);
#endif // WINDLOGTYPE_H
class binarySearchTree
#include <iostream>
#include <assert.h>
using namespace std;
template <class elemType> struct binaryTreeNode
{
elemType info;
binaryTreeNode<elemType>* llink;
binaryTreeNode<elemType>* rlink;
};
template <class elemType> class binarySearchTree
{
public:
const binarySearchTree<elemType>& operator=(const binarySearchTree<elemType>&);
void inorderTraversal(void (*visit) (elemType&));
binarySearchTree();
~binarySearchTree();
binaryTreeNode<elemType>* root;
private:
void inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType&));
};
template <class elemType> binarySearchTree<elemType>::binarySearchTree() {
root = NULL;
}
template <class elemType> void binarySearchTree<elemType>::inorderTraversal(void (*visit) (elemType& item))
{
inorder(root, *visit);
}
template <class elemType> void binarySearchTree<elemType>::inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType& item))
{
if (p != NULL)
{
inorder(p->llink, *visit);
(*visit)(p->info);
inorder(p->rlink, *visit);
}
}
class bst
#ifndef BST_H
#define BST_H
#include "binarySearchTree.h"
#include "windlogtype.h"
using namespace std;
class bst
{
public:
bst();
void InsertTree(windlogtype& newwind);
void printfunctions(windlogtype& x);
binarySearchTree<windlogtype>& GetTree();
void print(windlogtype& x);
private:
binarySearchTree<windlogtype> treeRoot;
};
#endif // BST_H
#include "bst.h"
bst::bst(){/*ctor*/ }
binarySearchTree<windlogtype>& bst::GetTree() { return treeRoot; }
void bst::print(windlogtype& x) { cout << x << " "; }
void bst::printfunctions(windlogtype& x)
{
treeRoot.inorderTraversal(print(windlogtype & x)); // error lies here
}
The
void bst::print(classdatatype& x) // is a member function
and
void print(classdatatype& x); // is a free function.
Hence the function pointers to hold them will be also different.
The OP has mentioned in the comments, that he/she wants to pass the member function print() from bst class to member functioninorderTraversal() of binarySearchTree<elemType> class. In that case passing the member-function is not sufficient, in addition to that the instance of the class to which the print function will be called also should be passed.
The Lambda function can come in handy to simplify this by capturing the instance of bst class and pass to the inorderTraversal() of the binarySearchTree class.
That means, inside template <class elemType> class binarySearchTree provide:
template<typename Callable>
void inorderTraversal(Callable visit)
{
inorder(root, visit); // simply pass visit further
// or avoid coping by warapping std::cref(): i.e. inorder(root, std::cref(visit));
}
template<typename Callable>
void inorder(binaryTreeNode<elemType>* p, Callable visit)
{
if (p != NULL)
{
inorder(p->llink, visit); // or inorder(root, std::cref(visit));
visit(p->info); // call directly with parameter
inorder(p->rlink, visit); // or inorder(root, std::cref(visit));
}
}
Inside the bst class
void printfunctions(windlogtype& x)
{
// lambda captures the instance by copy
const auto printThisLogType = [this](windlogtype & x)->void { this->print(x); };
treeRoot.inorderTraversal(printThisLogType); // pass the callable lambda
}
Here is compiling code: https://godbolt.org/z/jhCnPs
PS: The other error was from operator<< of windlogtype class where you missed to return the reference of std::ostream.
To be honest, you could have made a further simpler minimal code, by replacing windlogtype with int and showing the defenitions of the member function next to the declaration. That would make the code to read easily.

Template Inheritance issues

I have an Abstractqueue and I want to inherit it's members to another child class. When I try to create the child object in my main file I keep getting an undefined reference to `AbstractQueue::AbstractQueue()'
enter code here
#ifndef ABSTRACT_QUEUE_H
#define ABSTRACT_QUEUE_H
#include <iostream>
template <class Type>
class AbstractQueue
{
protected:
Type *items;
int front;
int back;
int capacity;
int count;
private:
// data goes here
public:
AbstractQueue(int s);
AbstractQueue(void);
~AbstractQueue(void);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
};
template <class Type>
AbstractQueue<Type>::AbstractQueue(int s){
items = new Type[s];
front = 0;
back = 0;
capacity = s;
count = 0;
std::cout << "made the abstract queue!" << std::endl;
}
template <class Type>
AbstractQueue<Type>::~AbstractQueue() {
delete[] items;
std::cout << "destructor called" << std::endl;
}
#endif
IncrementalQueue.h
#ifndef _INCREMENTALQUEUE_H
#define _INCREMENTALQUEUE_H
#include "Queue.h"
//#define SIZE = 10
#include <iostream>
template <class Type>
class IncrementalQueue : public AbstractQueue<Type>{
public:
//AbstractQueue(void);
//~AbstractQueue(void);
IncrementalQueue(int s);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
//~IncrementalQueue(void);
//AbstractQueue(void);
//AbstractQueue(int size);
//bool empty(void) ;
/*if (count == 0) {
return true;
}
else {
return false;
}*/
//int size(void);
//Type front throw(exception) {}
//Type dequeue(); //throw(exception) {}
//void enqueue ( Type e ) ;
//IncrementalQueue(int size);
};
template <class Type>
IncrementalQueue<Type>::IncrementalQueue(int s){
this->items = new Type[50];
this->front = 0;
this->back = 0;
this->capacity = 50;
this->count = 0;
std::cout << "made the incremental queue!" << std::endl;
}
#endif
main.cpp
#include "Queue.h"
#include "IncrementalQueue.h"
int main(){
IncrementalQueue<int> incqueue(50);
return 0;
}
I'm a little rusty with templates so I've been struggling at it for a couple of hours. does anybody have any clues on where my code can be failing?
IncrementalQueue::IncrementalQueue() constructor is calling the AbstractQueue::AbstractQueue() constructor and you have not defined it.
To make it compile you can just say AbstractQueue() = default; to have it generated by the compiler, if you are using C++11 or later, but that will not necessarily be correct (see the comments).
As it always happens with templates, you either need to put AbstractQueue::AbstractQueue() implementation (function body) to its header, or, if you know in advance all its possible template parameters, explicitly instantiate this function in cpp-file:
template class AbstractQueue<NeededType>;
In your case, it's impossible to know all possible template args in advance, so you need to put your function body to the header. That's the price of separate unit compilation.

Abstract Classes and virtual methods problems: cannot declare variable ‘list’ to be of abstract type ‘aStack<int>’ aStack<int> list(5)

Hi i am trying to implement an array based stack (in c++) but i have been stuck in it for a while. whenever i try to make an object in my source file, compiler generates the error "cannot declare variable ‘list’ to be of abstract type ‘aStack’
aStack list(5);" even though i aStack class is inheriting from ADT abs_stack. here's my code
enter code here
// question #1.
// ADT for stack.
template <class type>
class abs_stack {
public:
virtual void initialize_stack() = 0; // starts the stack.
virtual bool isEmpty() = 0; // checks whether stack is empty or not.
virtual bool isFull() = 0; // checks whether stack is full or not.
virtual void push(type n) = 0; //
virtual void pop() = 0;
virtual type top() = 0;
};
// declaring array based stack.
template <typename t>
//template <typename E>
// class AStack: public Stack<E>
class aStack : public abs_stack<t> {
private:
t *grid; // stack.
int max_stack_size;
int top_element; // points to the top of the stack.
void stack_copy(aStack<t> &copy); // used in copy contructor.
public:
aStack(int size); // paratmeterized constructor.
~aStack(); // destructor.
aStack(const aStack <t> &); // copy constructor.
const aStack<t> & operator =
(const aStack<t> &originalStack); // overloaded assignment operator.
//------------------------------------->
bool isEmpty() const;
bool isFull() const;
void pop();
void push(const t &newElem);
t top() const;
void initialize_stack();
};
enter code here
#ifndef H_stack
#define H_Stack
#include <iostream>
#include <cassert>
#include "stack.h"
using namespace std;
// stack methods' implementation.
template <class x> const aStack<x>& aStack<x>::operator=
(const aStack<x>& otherStack)
{
if (this != &otherStack) //avoid self-copy
copyStack(otherStack);
return *this;
}// end of overloaded assignment operator.
template <typename x>
void aStack<x> :: pop() {
if (!isEmpty()) {
top_element--; // decreases the position # of the top element.
}
else {
cout << "Error! Stack is already. Cannot remove anything." << endl;
}
} // end of pop()
template <typename x>
void aStack<x> :: push(const x &newElem) {
if (!isFull()) {
grid[top_element] = newElem; // places new element on the top
top_element++;
}
else {
cout << "No space available." << endl;
}
} // end of push
template <typename x>
x aStack<x> :: top() const {
assert(top_element != 0); // checks whether stack exists or not.
return grid[top_element - 1];
}
template <typename x>
void aStack<x>::initialize_stack() {
top_element = 0;
}
template <typename x>
bool aStack<x> :: isEmpty() const {
return (max_stack_size == 0);
}
template <typename x>
bool aStack<x> :: isFull() const {
return (top_element == max_stack_size);
}
template <typename x>
aStack<x> :: aStack(int size) {
if ( size <= 0) {
cout << "Error! Stack size can" <<
" never be lesser than/equal to 0." << endl
<< "Generating stack of size 10" << endl;
max_stack_size = 10;
}
else {
max_stack_size = size;
}
top_element = 0;
grid = new x[max_stack_size];
} // end of parameterized contructor.
template <typename x>
aStack<x> :: ~aStack() {
delete []grid;
grid = NULL;
max_stack_size = 0;
} // end of destructor.
template <typename x>
aStack<x> :: aStack(const aStack<x> &firstStack) {
grid = NULL;
stack_copy(firstStack);
} // end of copy contructor.
template <typename x>
void aStack<x> :: stack_copy(aStack<x> &copy) {
delete []grid;
grid = NULL;
max_stack_size = copy.max_stack.size;
top_element = copy.top.element;
grid = new x[max_stack_size];
// generating deep copy of the original stack.
for (int i =0; i < max_stack_size; i ++)
grid[i] = copy.grid[i];
} // end of stack copy.
#endif
#include <iostream>
#include "stack.h"
using namespace std;
//--------- source file-->
int main() {
aStack<int> list(5);
return 0;
}
The error implies that your class aStack is an abstract class, i.e. has at least one pure virtual method and therefore cannot be instantiated. That means that some of your aStack methods failed to participate in virtual overriding as a result of signature mismatch.
Notice that cv-qualifiers and ref-qualifires affect the parameter type and change the signature:
void f(int x)
void f(const int& x)
are considered different functions. Same goes for member functions cv-qualifiers, so only pop and initialize_stack retain original signature in your code.

Hash Table not accepting function passed into constructor in member init list

I have a hash table template that I have written for a class. I have a project due that relies on utilizing this hash table. It accepts an unsigned integer value to initialize the number of buckets it has, as well as a hash function to point to. I have not written that hash function yet, but I have a declaration for it. When I try to use the member initializer in my Game class for the hash table data member, it gives me an error that I don't understand.
Error 1 error C3867: 'Game::xorHash': function call missing argument list; use '&Game::xorHash' to create a pointer to member
2 IntelliSense: no instance of constructor "HTable<Type>::HTable [with Type=std::string]" matches the argument list
argument types are: (int, unsigned int (const std::string &s))
my Hash Table class is as follows:
#pragma once
#include "SLList.h"
template<typename Type> class HTable
{
public:
HTable(unsigned int numOfBuckets, unsigned int (*hFunction) (const Type &v));
~HTable();
HTable<Type>& operator=(const HTable<Type>& that);
HTable(const HTable<Type>& that);
void insert(const Type& v);
bool findAndRemove(const Type& v);
void clear();
int find(const Type& v) const;
private:
SLList<Type>* ht;
unsigned int (*hFunct) (const Type &v);
unsigned int numOfBuck;
};
template<typename Type>
HTable<Type>::HTable(unsigned int numOfBuckets, unsigned int (*hFunction) (const Type &v))
{
ht = new SLList<Type>[numOfBuckets];
this->numOfBuck = numOfBuckets;
this->hFunct = hFunction;
}
template<typename Type>
HTable<Type>::~HTable()
{
delete [] ht;
ht = nullptr;
}
template<typename Type>
HTable<Type>& HTable<Type>::operator=(const HTable<Type>& that)
{
if(this != &that)
{
delete [] this->ht;
this->hFunct = that.hFunct;
this->numOfBuck = that.numOfBuck;
this->ht = new SLList<Type>[numOfBuck];
for(unsigned int i = 0; i < this->numOfBuck; i++)
this->ht[i] = that.ht[i];
}
return *this;
}
template<typename Type>
HTable<Type>::HTable(const HTable<Type>& that)
{
this = *that;
}
template<typename Type>
void HTable<Type>::insert(const Type& v)
{
ht[hFunct(v)].addHead(v);
}
template<typename Type>
bool HTable<Type>::findAndRemove(const Type& v)
{
SLLIter<Type> iter(ht[hFunct(v)]);
for(iter.begin(); !iter.end(); ++iter)
{
if(v == iter.current())
{
ht[hFunct(v)].remove(iter);
return true;
}
}
return false;
}
template<typename Type>
void HTable<Type>::clear()
{
for(unsigned int i = 0; i < this->numOfBuck; ++i)
ht[i].clear();
}
template<typename Type>
int HTable<Type>::find(const Type& v) const
{
SLLIter<Type> iter(ht[hFunct(v)]);
for(iter.begin(); !iter.end(); ++iter)
{
if(v == iter.current())
return hFunct(v);
}
return -1;
}
My Game.h:
#pragma once
#include "stdafx.h"
#include "HTable.h"
#include "BST.h"
#include "DTSTimer.h"
using namespace std;
class Game
{
public:
Game(void);
virtual ~Game(void);
void refresh();
void input();
unsigned int xorHash(const string &s);
private:
string userInput;
DTSTimer timer;
BST<string> answers;
HTable<string> dictionary;
};
My Game.cpp (this is obviously just a skeleton, since I can't get the member init to work)
#include "Game.h"
Game::Game(void) : dictionary(2048, xorHash)
{
}
Game::~Game(void)
{
}
void Game::refresh()
{
}
void Game::input()
{
}
unsigned int Game::xorHash(const string &s)
{
return 0;
}
I've been working on this for a good while, and have been hitting a wall. I would really appreciate some help on how to get this thing up and running. Let me know if there is another snippet that needs to be seen (I've tried to be thorough in that regard).
You have two problems. The first is that you don't pass the member function pointer properly (the error message tells you exactly what do do). The other problem is that a function pointer is not the same as a member function pointer.
A member function pointer needs an instance object object to call the member function on. And this instance is passed as a hidden first argument, something that normal functions don't have.
For this you might instead turn to std::function and std::bind:
class HTable
{
public:
HTable(unsigned int numOfBuckets, std::function<unsigned int(const Type&)> hFunction);
...
private:
std::function<unsigned int(const Type&)> hFunct;
...
};
Then
Game::Game(void) : dictionary(2048, std::bind(&Game::xorHash, this))
{
}

What does "missing template argument" mean?

I'm pretty new to C++ and this site so there are bound to be errors. When I try to compile my code I get errors like error: missing template argument before 'b'. I've been searching the world for answers for hours and it has led me here.
My assignment is to implement a templated class Collection that stores a collection of
Objects using an array, along
with the current size of the collection.
#include <iostream>
#include "collection.h"
using namespace std; v
int main(int argc, char* argv[])
{
collection b; //<----error missing template argument before 'b'
return 0;
}
#ifndef COLLECTION_H
#define COLLECTION_H
#include <iostream>
template <typename obj>
class collection
{
public:
collection();
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
#include "collection.h"
template <typename obj>
collection<obj>::collection() :size(10)
{
col = new obj*[size];
}
template <typename obj>
bool collection<obj>::isEmpty() const
{
for(size_t k = 0; k < size; k++)
{
if(col[k] != NULL)
return false;
}
return true;
}
template <typename obj>
void collection<obj>::makeEmpty()
{
for(size_t k = 0; k < size; k++)
{
col[k] = NULL;
}
}
template <typename obj>
void collection<obj>::insert(obj val)
{
int temp = 0;
for(size_t s = 0; s < size; s++)
{
if(col[s] != NULL)
temp++;
}
if(temp >= size)
{
obj* temp = new obj*[size*2];
for(size_t c = 0; c < size; c++)
temp[c] = col[c];
delete col;
col = temp;
}
else
col[temp] = val;
}
template <typename obj>
void collection<obj>::remove(obj val)
{
for(size_t x = 0; x < size; x++)
{
if (col[x] == val)
{
for(size_t y = x; y < size-1; y++)
{
col[y] = col[y+1];
}
col[size-1] = NULL;
return;
}
}
}
template <typename obj>
bool collection<obj>::contains(obj val) const
{
for(size_t z = 0; z < size; z++)
{
if(col[z] == val)
return true;
}
return false;
}
You have to say what it's a collection of.
template <class A> class collection {}
requires that you use it as
collection<int> b;
or some appropriate type. That then makes a collection of ints. You haven't told it what you want a collection of.
First : Instantiate template by type. So if you have template <typename obj> class T {...}; you should use it like
void main {
T<int> t;
T<bool> t1; // .. etc
}
You can use a template with default value for the typename parameter defined in the class template declaration
template <typename obj = int> class T {/*...*/};
void main {
T<> t;
}
but anyway you should put empty angle brackets when use it without parameter.
Second: While declaring template, place it whole in the header file. Each definition of his methods should be in the file "*.h", don't ask me why, just don't split it to the header and "cpp" file.
Hope it helps.
Well, you're missing a template argument. You can't create a collection object, that's just a template.
You can only create e.g. a collection<int> or collection<std::string>.
You need to specify the type for template, like int or some other type:
collection<int> b;
There are a large number of errors in your code. First define your template in a header file:
In collection.h put the following:
#ifndef COLLECTION_H
#define COLLECTION_H
template <typename obj>
class collection
{
public:
collection() {}
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
Then in a .cpp file inside a main function do the following:
collection<int> b;
Instead of int you can use a different type but the main point is that YOU NEED A TYPE to instantiate a template.