C++ Invalid use of member function, did you forget the ( )? - c++

I'm working on an assignment where I create my own container using templates. The container I am required to use is called Smaph, which takes in two pairs of numbers and does a variety of functions with them. I am only allowed to make a header file for this assignment. I've created a singly-linked class slink, that takes one template argument.
Currently, I am trying to get a feel for templates and learning how to use them, so I have a very simple example I was hoping you could help me with. I have a push_back function in my singly linked list class to add to my templates. For some reason, I can't add things to my slink because I get a compile time error that says, Invalid use of member function, (push_back), did you forget the ( )? Can someone explain to me why I am getting this error?
Thank you!
template <typename T>
class slink {
private:
struct node {
T datum;
struct node *next;
};
node *head, *tail;
public:
slink() : head(0), tail(0) {
}
~slink() {
clear();
}
void push_back(const T &datum) {
node *p = new node;
p->datum = datum;
p->next = 0;
if (!tail)
head = p;
else
tail->next = p;
tail = p;
}
template <typename Tfirst, typename Tsecond>
class Smaph {
public:
Smaph();
~Smaph();
Smaph(const Tfirst a, const Tsecond b) {
std::pair<Tfirst, Tsecond> pair1(a, b);
s.push_back(pair1);
}
private:
slink<std::pair<Tfirst, Tsecond> > s();
};
And finally, my main to test my program. All I want to do right now is add these two numbers to my singly linked list through my Smaph.
int main() {
Smaph<int, double> s(3, 6.3);
}

slink<std::pair<Tfirst, Tsecond> > s();
This is a declaration of a function called s that takes no arguments and returns a slink<std::pair<Tfirst, Tsecond> >. When the compiler sees you do s.push_back(pair1);, it wonders what you're trying to do to that poor function. Remove the () to make it a data member:
slink<std::pair<Tfirst, Tsecond> > s;

On this line you did:
slink<std::pair<Tfirst, Tsecond> > s();
This is declaring a function named s that returns slink<std::pair<Tfirst, Tsecond> >. But then you did this inside one of your member functions:
s.push_back(pair1);
That isn't right, which is why your compiler alerts you of invalid use of this member function.
To fix, remove the parameters:
slink<std::pair<Tfirst, Tsecond> > s;

Related

Array of Generic Class Objects C++

I have a generic class Queue that contains a template Ttype2 as the placement holder for the type of data that will be stored in the information field of each node.
In my driver class I want to instantiate an array of Queue class objects but I can't seem to figure it out. How might I go about doing this?
These didn't work but illustrate what I'm trying to accomplish:
// Queue Complex[] = new Queue();//invalid use of template name without identifier list
//Queue<Ttype2> Complex[]; //template arg 1 is invalid
// vector<Queue> Complex2[];//invalid template arguments`
Queue Class declaration and constructor inside Queue.h header:
template <typename Ttype2>
class Queue
{
// Global Data Items
protected:
Node <Ttype2> Front, Rear;
int Length;
// member function prototypes
public:
Queue();
void AddRear(Node <Ttype2> ThisNode);
Node <Ttype2> RemoveFront();
void Modify(int Position, Node <Ttype2> ThisNode);
void ClearAll();
int GetSize();`
Node <Ttype2> GetNode(int Position);
Node <Ttype2>* toArray();
};`
// Constructor
template <typename Ttype2>
Queue <Ttype2> :: Queue()
{
Rear = Front = NULL;
Length = 0;
} // End of Constructor
`
This works:
Queue<int> *Complex = new Queue<int>();
Queue<int> Complex[1];
vector<Queue<int>> Complex2[1];
You need to give real params to your template when instantiating it.
Queue<Ttype2> // Ttype2 isn't a real type, use int, char, ...
Also you need to define your type Node<>. And if your want to assign NULL to Rear and Front it, first consider to make them pointers, second use nullptr instead of NULL.
I will add to Yola's solution that if I want to keep many different Queue<XXX> in a single array,
I usually create an interface class Queue_base.
class Queue_base{
public: virtual void func()=0;
};
template <typename Ttype2>class Queue : public Queue_base{
public: void func(){
//... some code
}
};
int main() {
Queue_base* complex[2];
complex[0]=new Queue<int>();
complex[1]=new Queue<float>();
complex[0]->func();
std::vector<Queue_base*> complex2;
complex2.push_back(new Queue<char>());
Queue<int>* c1=static_cast<Queue<int>*>(complex[0]);
return 0;
}
Here is live demo.
Note that using virtual function reduces performance a bit.
It will also lose the type (reduce to Queue_base*) and restrict some function calling, but it is useful for some real-world cases.
To extend its usage Node<T> can also inherit from a new class Node_Base that has all common function of Node<T>, e.g. :-
template <typename Ttype2> class Queue : public Queue_Base{
// Global Data Items
protected:
Node_Base* Front; //Front = new Node<Ttype2>();
Node_Base* Rear;
It depends on your demand though.

Issue with nested templated classes

I am trying to create a simple stack using templated classes. There seems to be an issue when one class calls the constructor of the other class.
#include <iostream>
#include <vector>
int g_MaxSize = 100;
template <class T>
class Stack;
template <class D>
class Node
{
private:
D data;
public:
Node(D value): data(value)
{
}
template <class T>
friend class Stack;
};
template <class T>
class Stack
{
private:
std::vector<Node<T>> stack;
int top;
public:
Stack(): stack(g_MaxSize), top(0)
{
}
void push(T val)
{
// make sure stack isnt full
stack[top++]= Node<T>(val);
}
Node<T> pop()
{
return stack[top--];
}
Node<T> peek()
{
return stack[top];
}
};
int main() {
Node<int> testNode(1) // *this works*
Stack<int> myStack;
myStack.push(3);
return 0;
}
The error is " No matching constructor for initialization of 'Node' ". As shown in the code above, Node constructor works on its own but it does not work when done through the Stack class.
The argument of vector needs a default constructor. Node is missing one, hence the error.
Your issue here is that stack(g_MaxSize) in Stack(): stack(g_MaxSize), top(0)
is requesting that you construct g_MaxSize default constructed Nodes in the vector. You can't do that though since Node is not default constructable.
You can add a default constructor to Node that will fix that. Another way would be to pass a default Node to the vector constructor like stack(g_MaxSize, Node<T>(1)). Lastly you could create the vector with zero size and then call reserve in the constructor body to allocate the storage for the Nodes without constructing them.

C++ method that can return different templated types

So I have 2 classes, a templated class named Node<T> and a nontemplated one named Context. I have a few methods in Context that need to return any type of Node<T>.
For instance, sometimes it will need to return a Node<double> and sometimes an Node<int> etc. I also have some methods that I’d like to have that take any type of Node<T> as a parameter.
Is there any way I can do this that doesn’t include having separate methods in Context for each possible case?
class Node
{
T Val;
public:
Node(T value) : Val(val) {}
T getVal() { return Val; }
}
class Context
{
Node<type>* divide(Node<type>* LHS, Node<type>* RHS)
{
type Solution LHS->getVal() / RHS->getVal();
return new Node<type>(Solution);
}
}
For instance, here, I want to return either a Node<double> if the answer ends up being a decimal, else I want to return a Node<int>. It will return a Node<double> with the solution as Node->Val; And other times, the operation will return an Node<int> (like 4/2) so it will return a Node<int> instead. This is a cut down example of what I want to do but its the same idea.
Polymorphism as intended with virtual methods can't be achieved in C++ if you need different return types.. unless you use something like boost::any or return opaque void *.
For the way C++ works, if you need different return types you need different signatures and hence 2 different methods, however C++ has syntactic sugar for letting the compiler handling that (templates) so that the coder have just to write 1 method once.
template < typename T>
class Node{
//...
};
class Container{
public:
template< typename T>
Node< T> * getNode(){
}
};
a possible implementation:
#include <stack>
#include <string>
#include <typeinfo>
class Container{
std::stack<void *> data;
std::stack<std::string> names;
public:
//push a node on the stack (you have to allocate it)
template< typename T>
void addNode( Node< T> * p){
data.push(static_cast<void*>(p));
names.push(typeid(T).name());
}
template< typename T>
Node< T>* removeNode(){
if(names.top()==typeid(T).name()){
names.pop();
Node< T>* node = reinterpret_cast<Node<T>*>(data.top());
data.pop();
return node;
}
return NULL; //returns nullptr;
}
};
of course, this is just a working example (provided you have Node defined somewhere). To show you a possible way (literally that's the simplest example I can think of, but you can improve performance and use it to design the solution to your problem).
Usage example:
Container c;
Node<double> n1* = new Node<double>(5.0);
Node<double> n2* = new Node<double>(3.0);
Node<int> n3* = new Node<int>(100);
c.addNode(n1);
c.addNode(n2);
c.addNode(n3);
//since I used a stack now I check node in reversed order
cout<< c.getNode<double>() == n3 <<endl; // false! n3 use "int"
cout<< c.getNode<int>() == n3 <<endl; //true!
cout<< c.getNode<double>() == n2 <<endl; //true!
cout<< c.getNode<int>() == n1 <<endl; //false! n1 use double
cout<< c.getNode<double>() == n1 <<endl; //true
delete n1;
delete n2;
delete n3;

Reversing a generic doubly-linked list in C++

I'm trying to give my generic list class a reverse function. For some reason, my algorithm ain't workin' when I test it. I thought it made sense: swap the pointers to the first and last nodes of the list, then go through the list and for each node swap its pointers to the previous and next node.
Go easy on me, guys. I'm trying to get some practice with generic programming. Teach me the ways of a C++ purist.
Here's the swap function:
template <class T> void swap(T* a, T* b) {
T* tempPtr = a;
a = b;
b = tempPtr;
}
Here's the reverse function:
template <class T> void List<T>::reverse() {
if (size > 1) {
swap(firstNodePtr, lastNodePtr);
node* curNodePtr = firstNodePtr;
while (curNodePtr != NULL) {
swap(curNodePtr->prevNodePtr, curNodePtr->nextNodePtr);
curNodePtr = curNodePtr->nextNodePtr;
}
}
}
Here's the class, its members and prototypes for functions:
template <class T> class List {
public:
List();
~List();
void push_back(T);
void push_front(T);
T get_at(unsigned);
unsigned get_size();
void reverse();
private:
struct node {
T val;
node* prevNodePtr;
node* nextNodePtr;
};
node* firstNodePtr;
node* lastNodePtr;
unsigned size;
};
Your swap<T> function does not work: it exchanges pointers, which are copied by value into local variables of your function, which has no effect in the caller.
Dropping your own swap and replacing it with std::swap will fix this problem.
Since you pass the two pointers by value, the changes to a and b don't propagate out of the swap() function, making it a no-op.
One way to fix it is by passing the pointers by reference:
template <class T> void swap(T*& a, T*& b) {
Alternatively (and preferably) just use std::swap() instead of your own function.
If you exposed your node structure (or at least a bidirectional iterator type for your list), you could avoid the whole issue and just use std::reverse.
List<int> someList;
// fill with data
std::reverse(someList.begin(), someList.end()); // where begin returns a bidirectional iterator for the head, and end returns a bidirectional iterator for 1 element beyond the tail

Generic list deleting non pointers

I have a generic list with a template
template<class t>
class GenericList {
//the data is storeed in a chained list, this is not really important.
struct c_list { t data; c_list* next; ...constructor... };
public:
bool isDelete;
GenericList() : isDelete(false) {...}
void add(t d) {
c_list* tmp = new c_list(d, first->next);
//this is not really important again...
}
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
if (isDelete) { delete tmp->data; } //important part
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
The important part is the isDelete
This is only a sample code
I need this because I want to store data like this:
GenericList<int> list;
list.add(22);list.add(33);
and also
GenericList<string*> list;
list.add(new string("asd")); list.add(new string("watta"));
The problem if I store only <int> the compiler said that I cannot delete non pointer variables, but I don't want to in this case. How can I solve this?
when I store <int*> there is no compiler error...
Without changing much your code, I would solve your problem as
template<class t>
class GenericList
{
//same as before
//add this function template
template<typename T>
void delete_if_pointer(T & item) {} //do nothing: item is not pointer
template<typename T>
void delete_if_pointer(T* item) { delete item; } //delete: item is pointer
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
delete_if_pointer(tmp->data); // call the function template
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
EDIT: I just noticed that #ildjarn has provided similar solution. However there is one interesting difference: my solution does NOT require you to mention the type of data when calling the function template; the compiler automatically deduces it. #ildjarn's solution, however, requires you to mention the type explicitly; the compiler cannot deduce the type in his solution.
I would create a nested struct template inside your class to help:
template<typename U>
struct deleter
{
static void invoke(U const&) { }
};
template<typename U>
struct deleter<U*>
{
static void invoke(U* const ptr) { delete ptr; }
};
Then change the line that was using isDelete from
if (isDelete) { delete tmp->data; }
to
if (isDelete) { deleter<t>::invoke(tmp->data); }
delete on an int makes a program ill-formed, so the compiler will reject it, even though the delete would never be reached.
What you want is only possible if you switch from "bare" pointers to smart pointers such as unique_ptr or shared_ptr; those handle memory management for you, without explicit delete.