How to pass functions as parameters within a class? - c++

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.

Related

Need help implementing a SmartPointer

I'm having trouble implementing a smart pointer in C++ for an assignment.
My code is supposed to create two SmartPointers. The first points to 1 and the second initially points to 3 but is changed to 10. My code should print out
intOne: 1
intTwo: 10
but instead it prints out
intOne: 10
intTwo: 4919984
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <exception>
using namespace std;
template <typename T>
class SmartPointer
{
public:
SmartPointer(T in)
{
try
{
if(in<0)
{
throw "SmartPointer does not handle negative numbers";
}
T * val = &in;
this->data = val;
}
catch(exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
}
~SmartPointer()
{
delete data;
}
T getValue();
void setValue(T val);
private:
T*data;
};
template <typename T> T SmartPointer<T>::getValue()
{
return *this->data;
}
template <typename T> void SmartPointer<T>::setValue(T val)
{
if(val<0)
{
throw "SmartPointer does not handle negative numbers";
}
this->data = &val;
}
int main()
{
SmartPointer<int> intOne(1);
SmartPointer<int> intTwo(3);
intTwo.setValue(10);
cout<<"intOne: "<<intOne.getValue()<<endl;
cout<<"intTwo: "<<intTwo.getValue()<<endl;
}
Your constructor takes a T by value and then attempts to set the internal pointer to the local copy of the value. It should take the address of a T instead.
Your exception stuff is unnecessary, since the class doesn't even know what type is T, so it could be some type that does not have a comparison operator with an int. Even if you do need to throw exceptions, they should be caught in main(), since nobody expects a constructor to print error messages to the screen. throw "message" is wrong, since you're trying to throw an instance of const char*. Instead, call the constructor of one of the standard exceptions like throw domain_error("message").
Using this-> does not really do anything other than make it slower to type.
In case you didn't know, using endl flushes the buffer. If you don't need it, use '\n'.
The fixed code:
//#include <stdio.h> Why?
//#include <stdlib.h>
#include <iostream>
#include <exception>
using namespace std;
template<typename T>
class SmartPointer
{
public:
SmartPointer(T *in);
~SmartPointer();
T getValue();
void setValue(const T &val);
private:
T *data;
};
template<typename T> SmartPointer<T>::SmartPointer(T *in) //Moved implementation outside of class declaration
{
//Completely unnecessary exception stuff
data = in; //this-> is unnecessary
}
template<typename T> SmartPointer<T>::~SmartPointer()
{
delete data;
}
template<typename T> T SmartPointer<T>::getValue()
{
return *data;
}
template<typename T> void SmartPointer<T>::setValue(const T &val)
{
//More unnecessary exception stuff
*data = val;
}
int main()
{
SmartPointer<int> intOne(new int); //The constructor should take a pointer for the object to store instead of an value
SmartPointer<int> intTwo(new int);
intOne.setValue(1);
intTwo.setValue(10);
cout << "intOne: " << intOne.getValue() << '\n'; //endl flushes the buffer, kind of unnecessary here
cout << "intTwo: " << intTwo.getValue() << '\n'; //since it gets flushed upon the program exiting anyways
}

c++ class function as argument to another class function

I am trying to pass a templated member function of one class as an argument of a templated member function of another class. I've seen several examples of using function pointers, but i am trying to pass this function argument directly.
in
template <class Item>
class MinHeap
i have the function
tempmlate <class Item>
template <class Process>
void inorder (Process f, const int index)
{
if (index < size())
{
inorder(f, index*2 +1);
f(data[index]);
inorder(f, index*2 +2);
}
}
and in
template<item>
class sequ
i have a function called
void insert(const Item& x);
I'm trying to do this in main:
MinHeap<int>* tree = new MinHeap<int>();
//insert some stuff
sequ<int>* s = new sequ<int>();
tree->inorder(s->insert);
but the last line gives me the error:
error: reference to non-static member function must be called
tree->inorder(s->insert);
when i replace s->insert with the function, print
void print(int x)
{
printf("%d\n", x);
}
it works fine.
how do i use a member function as argument?
&sequ<int>::insert gives you a pointer to the the member function insert of the sequ<int> class. However, to call a member function you also need an instance of the class. Said another way, you cannot perform f(data[index]); in the inorder function because you need an object instance to call the f member function.
Example Code
#include <iostream>
#include <string>
#include <vector>
template<typename T>
class Bar
{
public:
void barFn(const std::string& data) { std::cout << "Bar<T>::barFn: " << data << "\n"; }
};
template<typename T>
class Foo
{
public:
Foo() : mData{ "Hello World" } {}
template<typename C, typename F>
void fooFn(C* instance, F memFn, size_t n)
{
(instance->*memFn)(mData[n]);
}
private:
std::vector<std::string> mData;
};
int main()
{
Bar<int> bar;
Foo<int> foo;
foo.fooFn(&bar, &Bar<int>::barFn, 0);
return 0;
}
Example Output
Bar<T>::barFn: Hello World
Live Example

initialize a member of some class in initialization list if the member is a template class

[Solved]: The problem was not in template class initialization, but with code-specific issue of using undefined macro inside a template class constructor. The compiler error did not complain about undefined symbol, but was (wrongfully) related to lambdas.
I've searched for an answer but couldn't find an exact one. The closest answer is here: C++ invoke explicit template constructor but I'm not sure if that is entirely related to my question.
And my question is, how can I initialize a member of structure B in initialization list if the member is a template class?
Header ClassA.h:
#ifndef _A_
#define _A_
#include <typeinfo>
#include <windows.h>
template<class Type> class A{
int u,v;
Type** pointer;
public:
A();
A(int number);
~A();
Type& operator[] (int i){
typeid(Type);
return *pointer[i];
}
Type& Get(int i)
{
typeid(Type);
return *pointer[i];
}
Type *GetPointer(int i)
{
typeid(Type);
return pointer[i];
}
Type* add ();
Type& add(Type *element);
Type& add(Type *element, int place);
void expand(int NewLength);
void swap(Type *element, int place);
void remove(int number);
void remove(Type *element);
void removePointer(int number);
void removePointer(Type *element);
};
template<class Type>A<Type>::A(){
u = 128;
v = 10;
}
template<class Type>A<Type>::A(int number){
//some thing to do with number;
u = number;
v = 10;
New( pointer, Type *[u] );
}
template <class Type> A<Type>::~A()
{
}
template <class Type> void A<Type>::expand(int NewLength)
{
Type **NewList = NULL;
NewList = new Type*[NewLength];
}
template <class Type> Type* A<Type>::add ()
{
pointer[u] = new Type;
}
template <class Type> Type& A<Type>::add(Type *element)
{
}
template <class Type> Type& A<Type>::add(Type *element, int place)
{
}
template <class Type> void A<Type>::swap(Type *element, int place)
{
}
template <class Type> void A<Type>::remove(Type *element)
{
}
template <class Type> void A<Type>::removePointer(int nume)
{
}
template <class Type> void A<Type>::removePointer(Type *element)
{
}
#endif
Header StructB.h:
#pragma once
#ifndef _B_
#define _B_
#include "ClassA.h"
struct C{
float x,y,z;
};
struct B{
private:
B(){
}
public:
int x,y;
A<B*> member1;
A<C> member2;
B(int X,int Y) : member1(5),member2(5) {
//initialize x,y
}
void Add(B* otherB){
B** _pOtherB = new B*; (*_pOtherB) = otherB;
member1.add(_pOtherB);
}
};
#endif
The compiler complains with this error (and some other errors, I can post them if nedded):
error C3493: 'number' cannot be implicitly captured because no default capture mode has been specified
Is there any way to do this, or some workaround perhaps?
Thanks in advance :D
Either the code you've given us isn't complete, or it is broken. This line:
New(pointer, Type *[u]);
seems to be referencing either some missing member method or global function, or it is simply invalid. The error message is kinda cryptic, but that's C++ for you.
I'm going to assume that New is some kind of macro, because no normal function (even a templated one) can take this sort of type definition as a parameter. You've not given us the definition of New, so there's no way we can tell. It is probably the absense of this macro (maybe a wrapper for some sort of memory debugging system?) that is causing the crazy error.
If I replace the New line with this:
pointer = new Type*[u];
the code compiles fine.

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))
{
}

Class member calls function template with callback function

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