C++ function pointer in template - c++

I've been assigned the following template:
#include <map>
template <typename T>
class Catalog {
struct Item {
//..
};
std::map<int, Item*> items;
public:
Catalog(void);
Catalog(const Catalog&);
~Catalog(void);
bool IsEmpty(void) const;
int Size() const;
void Add(T*);
T* Remove(T*);
T* Find(T*);
typedef void (T::*pFunc) (const T&);
void Inspection(pFunc) const;
};
Next, there is an abstract Product class and three subclasses:
class Product {
protected:
unsigned int _id;
string _name;
public:
Product(const int& id, const string& name) : _id(id), _name(name) {};
virtual void Action(const Product& p) = 0;
virtual int hashCode() {
return _id*100;
};
unsigned int getId(void) const {return _id;};
string getName(void) const {return _name;};
};
class ProductA : public Product {
public:
ProductA(const int& id, const string& name) : Product(id, name) {};
virtual void Action(const Product& p) {
cout << "ahoj" << endl;
};
};
Finally, class ProductsCatalog that handles a Catalog instance:
class ProductsCatalog {
Catalog<Product> catalog;
public:
//..
void CatalogInspection(void) const {
catalog.Inspection(&Product::Action);
}
};
What I have trouble with is the Inspection method:
template <typename T> void Catalog<T>::Inspection(pFunc p) const {
for (std::map<int, Item*>::const_iterator it=items.begin(); it!=items.end(); ++it) {
it->second->Product->*p(*(it->second->Product));
}
};
I am getting the following error:
error C2064: term does not evaluate to a function taking 1 arguments
I've tried everything I could think of, without success. The following works as intended, but is obviously not abstract enough:
it->second->Product->Action(*it->second->Product);

Did you try
(it->second->Product->*p)(*(it->second->Product));
for calling the method?
The thread Calling C++ class methods via a function pointer seems to be related.

Related

Custom set comparison function in a template class

I was trying to figure out this exercise from a school exam.
They implemented an abstract template Book class, and the assignment is to implement a bookshelf class.
I tried to construct a set of book pointers with a custom comparator, but then I encounter a compilation error:
In template: reference to type 'const Book<std::basic_string<char>>' could not bind to an lvalue of type 'const std::_Rb_tree<...>
(I implemented a sub class BOOK2 just for debugging purposes)
This is the long given book abstract class
#include <iostream>
#include <set>
#include <string>
#include <utility>
template <class T>
class Book
{
// any member variables are inaccessible to descendants
private:
std::string _title; // do not call a copy-ctr
T _author; // do not call a copy-ctr
size_t _number_of_pages;
public:
Book(std::string title,
T author,
size_t number_of_pages)
: _title(std::move(title)),
_author(std::move(author)),
_number_of_pages(number_of_pages)
{}
virtual ~Book() = default;
const std::string& get_title() const
{ return _title; }
const T& get_author() const
{ return _author; }
size_t get_number_of_pages() const
{ return _number_of_pages; }
public:
virtual Book<T>* clone() const = 0; // implemented *only* by descendent classes
virtual bool is_available_on(const std::string& platform) const = 0; // implemented *only* by descendant classes
protected:
virtual void do_output(std::ostream& os) const // can be overridden; can be accessed *only* by descendants
{
os << _title << ", " << _author << ", " << _number_of_pages << " pages";
}
// output should depend on who book really is
friend std::ostream& operator<<(std::ostream& os, const Book& book)
{
book.do_output(os);
return os;
}
};
This is what I implemented:
class Book2: public Book<std::string>{
public:
Book2(std::string &title,
std::string &author,
size_t number_of_pages)
: Book<std::string>(title,author,number_of_pages){}
bool is_available_on(const std::string &platform) const override{return
true;}
Book<std::basic_string<char>> * clone() const override{
Book<std::basic_string<char>> * a{};
return a;
}
};
template<class TP>
static bool book_comp(const Book<TP>& a,const Book<TP> & b){
return a.get_title()<b.get_title();}
template<class TT>
class Bookshelf
{
public:
typedef bool(*book_comp_t)(const Book<TT>& a,const Book<TT> & b);
// DO NOT CHANGE NEXT TWO LINES:
auto& get_books() { return _books; } // DO NO CHANGE
auto& get_books() const { return _books; } // DO NO CHANGE
Bookshelf():_books(book_comp<TT>){}
void add(Book<TT>& book)
{
size_t init_size=_books.size();
_books.insert (&book);
if(init_size==_books.size()){
throw std::invalid_argument("book already in bookshlf");
}
}
// sorted lexicographically by title
friend std::ostream& operator<<(std::ostream& os, const Bookshelf<TT>&
bookshelf)
{
for(const auto& book :bookshelf._books)
{
os << *book << std::endl;
}
}
private:
std::set<Book<TT>*,book_comp_t> _books;
};
int main ()
{
std::string a ="aba";
std::string bb ="ima;";
Book2 b = Book2(a, bb, 30);
Bookshelf<std::string> shelf;
std::cout<<b;
shelf.add(b);
}
I tried changing the const qualifiers in some places, and it didn't work.
I also tried without using the custom comparator function which worked ok.
I think this is probably some syntax error maybe?
std::set<Book<TT>*,book_comp_t> _books; is a set of Book<TT>*, and thus requires a comparator whose parameters are of type Book<TT>*, not const Book<TT>&

How should i overload += operator in a vector template?

I got a template class Atlas that will store objects of Animal class and derived classes of Animal;
here's the code:
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
std::string m_name;
Animal (std::string name): m_name {name} {}
public:
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
virtual std::string regn() const { return "nevertebrate";}
virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
/* std::string m_name;
Vertebrate (std::string name)
:m_name {name} {} */
Vertebrate (std::string name)
: Animal {name} {}
public:
virtual std::string regn() const { return "vertebrate";}
virtual ~Vertebrate(){
cout<<"Destructor vertebrate"<<'\n';};
};
class bird: public Vertebrate {
public:
bird(std::string name)
: Vertebrate{ name }{}
void set_name (std::string nume){
m_name = nume;}
std::string get_name(){
return m_name;}
virtual std::string regn() const {return "pasare";}
virtual ~bird (){
cout << "destructor bird"<<'\n';}
};
template <class T>
class Atlas
{
private:
int m_length{};
T* m_data{};
public:
void SetLength(int j);
Atlas(int length)
{
assert(length > 0);
m_data = new T[length]{};
m_length = length;
}
Atlas(const Atlas&) = delete;
Atlas& operator=(const Atlas&) = delete;
~Atlas()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
m_data = nullptr;
m_length = 0;
}
T& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const
{
return m_length;
}
template <class T>
void Atlas<T>::SetLength(int j){m_length = j;
}
int main()
{
Atlas<Bird> AtlasBird(10);
Bird b;
AtlasBird.SetLength(11);
AtlasBird[10] = b --- it gets a memoryleak from here.
return 0;
}
I want to overload the += operator so that i can insert a new object into my Atlas, (e.g. AtlasAnimal).
I tried with the SetLength function to increase the length, (e.g. AtlasAnimal.SetLength(11)) but when i try to assign AtlasAnimal[10] an object (e.g. Bird b) it drops a memory leak.
I'm sorry if there was a similar question answered, but i couldn't find anything that helps

Can't "store member function" in template [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to "store member function in my class" in order to call it later in some cases. But I can't fix my code for storing member functions with parameters. Heres is my code:
class IMemFn
{
public:
IMemFn() {}
IMemFn(const IMemFn& other) = delete;
IMemFn& operator=(const IMemFn& other) = delete;
IMemFn(IMemFn&& other) = delete;
IMemFn& operator=(IMemFn&& other) = delete;
virtual ~IMemFn() {}
virtual void func(const std::string& name, const std::string& value) = 0;
};
template<typename ReturnType, class Class>
class MemFn final : public IMemFn
{
public:
typedef ReturnType(Class::*Method)();
MemFn(Class* object, Method method) : IMemFn(), m_object(object), m_method(method) {};
virtual void func(const std::string& name, const std::string& value) override final
{
(m_object->*m_method)(name, value);
};
private:
Class* m_object;
Method m_method;
};
class Test
{
public:
template <class Class, typename Method>
void addMemFn(Class* obj, Method method) {
auto memFn = new MemFn<typename std::result_of<decltype(method)(Class)>::type, Class>(std::forward<Class*>(obj), std::forward<Method>(method));
m_memFns.push_back(memFn);
}
private:
std::list<IMemFn*> m_memFns;
};
class SomeClass
{
public:
void funcAll(const std::string& name, const std::string& value) { std::cout << "SomeClass func"; }
};
class SomeClass2
{
public:
void func2(const std::string& name, const std::string& value) { std::cout << "SomeClass2 func"; }
};
int main()
{
Test test;
SomeClass someClass;
SomeClass2 someClass2;
test.addMemFn(&someClass, &SomeClass ::funcAll);
test.addMemFn(&someClass2, &SomeClass2::func2);
return 0;
}
But compilation fails with this message: 'type': is not a member of 'std::result_of<Method (Class)>
and in this line: (m_object->*m_method)(name, value);
But if I try to save member function without parameters, then this error doesn't appear.
Thanks for any help!
Several changes required here to make it compile:
Firstly std::result_of<decltype(method)(Class) needs to be std::result_of<Method(Class*,std::string,std::string)
because it is a member function taking a pointer to this plus two arguments.
It looks like function inform in MemFn should be renamed func.
Method needs to be added as a template argument of MemFn.
Then you can invoke the member functions through the test object, for example:
(*test.m_memFns.begin())->func("a", "b");
However you will not be able to return different types from these member functions while also satisfying the interface void IMemFn::func(...).
Thank's everybody for your answers! Seems I'm very tired 'cause of these damn tamplates. I used std::functions with std::bind and everything now is simple and light. So, my final code is:
class Test
{
public:
template <class Class, typename Method>
void addMemFn(Class* obj, Method method) {
auto func = std::bind(method, obj, std::placeholders::_1, std::placeholders::_2);
m_funcs.push_back(func);
}
private:
std::list<std::function<void(const std::string&, const std::string&)>> m_funcs;
};
class SomeClass
{
public:
void funcAll(const std::string& name, const std::string& value) { std::cout << "SomeClass func"; }
};
class SomeClass2
{
public:
void func2(const std::string& name, const std::string& value) { std::cout << "SomeClass2 func"; }
};
int main()
{
Test test;
SomeClass someClass;
SomeClass2 someClass2;
test.addMemFn(&someClass, &SomeClass::funcAll);
test.addMemFn(&someClass2, &SomeClass2::func2);
return 0;
}

C++ Pass a argument through a class with array index?

class cat
{public:
void dog(int ID, char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
}
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
I want something similar to this.
include <vector>
class CatArray;
class Cat {
// This line means that the CatArray class can
// access the private members of this class.
friend class CatArray;
private:
static int ID;
public:
void dog(const char* value) {
// Use ID here any way you want.
}
};
int Cat::ID = 0;
class CatArray {
private:
std::vector<Cat> cats;
public:
explicit CatArray(unsigned int size) : cats(size) {}
Cat& operator [](unsigned int index) {
Cat::ID = index;
return cats[index];
}
};
But a little different. There are 18 Clients in a game and i need to basically do this. for eg, "Client 4 Chooses an option and the option gets called through the array index and than that way client 4 will call the function with the function holding the index 4"
Then cats[1] is not really a Cat object but a CatWithIndex object:
class Cat {
public:
void dog(size_t index,const char* value);
};
class CatWithIndex {
size_t index_;
const Cat &cat_;
public:
CatWithIndex(size_t index, const Cat &cat): index_(index), cat_(cat) {}
void dog(const char* value) {
cat_.dog(index_,value);
}
};
class CatArray {
private:
std::vector<Cat> cats;
public:
Cat& operator [](unsigned int index) {
Cat::ID = index;
return CatWithIndex(index,cats[index]);
}
};

C++ cannot instantiate abstract class

I am new to C++. Could you pls help me get rid of the errors:
error C2259: 'MinHeap' : cannot instantiate abstract class
IntelliSense: return type is not identical to nor covariant with return type "const int &" of overridden virtual function function
template <class T> class DataStructure {
public:
virtual ~DataStructure () {}
virtual bool IsEmpty () const = 0;
virtual void Push(const T&) = 0;
virtual const T& Top() const = 0;
virtual void Pop () = 0;
};
class MinHeap : public DataStructure<int>
{
private:
std::vector<int> A;
public:
bool IsEmpty() const
{
..
}
int Top() const
{
..
}
void Push(int item)
{
...
}
void Pop()
{
..
}
};
The problem is with const T& Top() vs. int Top(). The latter is different from the former, and thus not an override. Instead it hides the base class function. You need to return exactly the same as in the base class version: const int& Top() const.
The same problem exists for Push(), BTW.
try
class MinHeap : public DataStructure<int>
{
private:
std::vector<int> A;
public:
bool IsEmpty() const
{
..
}
const int& Top() const
{
..
}
void Push(const int& item)
{
...
}
void Pop()
{
..
}
};
Note that it is using const int& instead of int for Top and Push