C++ function pointer in constructor - c++

I am trying to pass a function pointer in to a constructor of a class. However, when I try to compile the code, I am getting an error. The code and error are :
quickfind.h
#ifndef QUICKFIND_H
#define QUICKFIND_H
#endif // QUICKFIND_H
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind<T>(int n,int (*ptr)(const void *));
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
Constructor definition in file quickfind.cpp
template <class T>
QuickFind<T>::QuickFind(int n,int (*ptr)(const void *))
{
size=n;
array=new int[n];
giveIndex=ptr;
for(int i=0;i<n;i++)
{
array[i]=i;
}
}
In my main function file :
int giveIndex (const void *ptr)
{
temp *tptr=(temp*)ptr;
return tptr->getA();
}
int main()
{
QuickFind<temp> *qf=new QuickFind<temp>(10,giveIndex);
}
Here, I am getting 'undefined reference to QuickFind<temp>::QuickFind(int, int (*)(void const*))' error. I am not able to figure out the problem...please help.

One thing wrong, you don't need the on the constructor:
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind(int n,int (*ptr)(const void *)); /// <---- here, no <T>
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
In your case, the class it templated, but this function isn't. And, template functions must be defined in the header file so that the file that includes them can see the code and substitute the parameter types.

Put all of the following in one CPP file to see it work. As noted in other comments you must, for templated classes, put the entire definition in the header file. Do not separate the function declaration from its definitions into a separate CPP file. In this case having the entire implementation in the one CPP file serves the same purpose.
I have made some changes to your code to make it typesafe, memory leak safe and more exception safe. For example I replaced your dynamically allocated array with std::vector. std::vector has all the features you need but manages the memory for you and will be cleaned up when your class goes out of scope.
#include <vector>
#include <iostream>
#include <functional>
template <typename T>
class QuickFind
{
private:
std::vector<int> data;
std::function<int (const T&)> func;
public:
QuickFind(int n, std::function<int (const T&)> f) : data(n), func(f)
{
int i = 0;
for(auto it = data.begin(); it != data.end(); ++it)
data[i]=i++;
}
void connect (const T& u, const T& v)
{
std::cout << func(u) << "\n";
std::cout << func(v) << "\n";
}
bool isConnected(const T* u,const T* v);
};
class temp
{
int val;
public:
temp(int i) : val(i)
{}
int getA() const
{
return val;
}
};
int giveIndex (const temp &t)
{
return t.getA();
}
int main()
{
temp t1(5), t2(10);
QuickFind<temp> qf1(10,giveIndex);
qf1.connect(t1, t2);
// this example uses a lambda as the callback
auto giveIndex2 = [](const temp& t) { return t.getA(); };
QuickFind<temp> qf2(20, giveIndex2);
qf2.connect(t1, t2);
}

The compiler wants to know objects of which types will be instantiated from a template class at the time of compilation of template class methods. So, there may arise compile-time or link-time errors.
This explains more about various errors and their causes.
Adding #include "quickfind.cpp" in the end of the header file worked in my case after some efforts.

Related

C++ Best way to have class member which is a pointer (or reference) to another class and can handle both const and non-const situations

Consider the following sample code. It compiles and works as expected. However, if I add "const" to the beginning of the first line of main function, it will not compile, because B class takes a pointer to A, and with const being added, we will have a pointer to const A instead. Templatizing B is an option, but I wonder if there are cleaner/nicer solutions for this. I am open to various suggestions, including moving the B inside A if that would help (B is used by A only).
#include <vector>
template <typename T>
class B;
template <typename T>
class A{
friend class B<T>;
std::vector<T> data;
public:
A(int n) {
data.resize(n); for (int i = 0; i < n; i++)
data[i] = static_cast<T>(i);
}
B<T> getB(int pos) {return B<T>(this, pos);}
const B<T> getB(int pos) const {return B<T>(this, pos);}
};
template <typename T>
class B {
A<T>* pointerToA;
int pos;
public:
B(A<T>* pointerToA_, int pos_) : pointerToA(pointerToA_), pos(pos_) {}
T& get() const { return pointerToA->data[pos]; }
T& get() { return pointerToA->data[pos]; }
};
int main() {
A<int> a(10); // const A<int> a(10); will not compile!
int& i = a.getB(3).get();
}

error: 'template<class T> class Dynamic_Array' used without template parameters

I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}

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

avoid code duplication in template functions used to distinguish between const and non-const

In writing a program, I've come up with a piece of code that I cannot manage to make code-duplication free.
#include <iostream>
using namespace std;
class Presenter{
public:
template <typename T>
void addField(T& t){
cout << "do something that could happen to modify t" << endl;
}
template <typename T>
void addField(const T& t){
cout << "do something that cannot possibly happen to modify t" << endl;
}
};
class Presented{
public:
Presented() : a(0), b(0.) {}
void bind(Presenter& p){
p.addField(a);
p.addField(b);
//...
}
void bind(Presenter& p) const {
p.addField(a);
p.addField(b);
//...
}
private:
int a;
double b;
//...
};
int main() {
Presenter presenter;
Presented p1;
const Presented p2;
p1.bind(presenter);
p2.bind(presenter);
}
Here is a simple dummy program which shows the issue. As you see, the code of the two bind functions is (looks) exactly the same. Of course it is not, since two different functions (addField) are used, which only happen to share the name.
Nonetheless, I have been looking for a way to remove the need to verbatim write the void bind(Presenter& p) const.
Does anyone see a method for reaching the goal? I wasn't able to come up with one.
Delegate to a template that can be called with a const or a non-const instance of Presented:
class Presented{
public:
Presented() : a(0), b(0.) {}
void bind(Presenter& p){
bindImpl(p, *this);
}
void bind(Presenter& p) const {
bindImpl(p, *this);
}
private:
template<typename P>
static void bindImpl(Presenter& p, P& presented)
{
p.addField(presented.a);
p.addField(presented.b);
}
int a;
double b;
};