Cannot convert argument from 'variable' to 'const T &'

Howdy. I am using a doubly linked list to obtain requests from an input file and eventually place them into an array of queues based on priority. When reading in each request, I am supposed to create a Struct (which is predefined by my professor) and enqueue it into the doubly linked list.
Here is the struct definition:
1
2
3
4
5
6
struct reqNode {
  int         timestamp;
  std::string name;
  Status      status;
  int         duration;
};

Here is the snippet from the header file that defines the function used:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <typename T>
void Dlist<T>::InsertBack(const T& o) {
  if (IsEmpty()) {
    node* newnode = (node*)malloc(sizeof(node));
    if (newnode == NULL) {
      std::cout << "Overflow detected" << std::endl;
    }
    else {
      newnode->o = o;
      newnode->prev = NULL;
      newnode->next = NULL;
      first = newnode;
      last = newnode;
    }
  }
  node* newnode = (node*)malloc(sizeof(node));
  newnode->o = o;
  last->next = newnode;
  newnode->prev = last;
  newnode->next = NULL;
  last = newnode;
}

And here is the function returning the error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void ObtainRequests(Dlist<reqNode*> &requests) {
  std::string input = " ";
  std::cin >> input;
  int node_count = std::stoi(input);
  for (int i = 0; i < node_count; i++) {
    std::string temp[4];
    int count = 0;
    std::cin >> temp[0];
    std::cin >> temp[1];
    std::cin >> temp[2];
    std::cin >> temp[3];
    struct reqNode newnode;
    newnode.timestamp = std::stoi(temp[0]);
    newnode.name = temp[1];
    if (temp[2] == "regular") {
      newnode.status = NONE;
    }
    else if (temp[2] == "silver") {
      newnode.status = SILVER;
    }
    else if (temp[2] == "gold") {
      newnode.status = GOLD;
    }
    else {
      newnode.status = PLATINUM;
    }
    newnode.duration = std::stoi(temp[3]);
    requests.InsertBack(newnode);
  }
}

The specific error message is: Error C2664 'void Dlist<reqNode *>::InsertBack(const T &)': cannot convert argument 1 from 'reqNode' to 'const T &'
I understand that I need to modify either the line containing 'struct reqNode newnode' or 'requests.InsertBack(newnode)', but adding a pointer to the latter gives me a different error: Error C2228 'left of '.timestamp' must have class/struct/union' and adding a pointer to the former maintains the original error while also telling me that references to newnode must be initialized. I was under the impression that using Template T in my classes would allow me to use any variable type in my .cpp, but there seems to be an additional step here that I'm missing. If anyone can clue me in on the matter it would be much appreciated.
I was under the impression that using Template T in my classes would allow me to use any variable type in my .cpp

For requests you have specified that T is reqNode*.

1
2
3
4
void ObtainRequests(Dlist<reqNode*> &requests) {
                          ~~~~~~~~
                              ^
                              T
Last edited on
That is correct. So I am confused as to why, when I use requests.InsertBack(newnode) where newnode is of struct reqNode, that I am getting this error.
The variable that requests should accept as its node is the reqNode struct, yet it refuses to do so.
The function expects a pointer to a reqNode but you're passing it a reqNode.

You could change it to requests.InsertBack(&newnode);. That'll compile (I think) but it's probably not what you want. newnode is a local variable and will go out of scope on the next line leaving an invalid pointer inside your linked list.

What I think you probably mean is to store reqNode objects inside the linked list (not pointers to reqNode objects). In that case you should change the type of requests to Dlist<reqNode>& (i.e. remove the asterisk).

 
void ObtainRequests(Dlist<reqNode> &requests) {

Then the linked list will store a copy of the newnode object that you passed to InsertBack.

 
newnode->o = o; // the copying happens here  

That said, if you get the code to compile you'll probably notice that the InsertBack function isn't correct. It looks like it will insert two nodes if the list is empty. I haven't looked in detail so I could be missing something.
Last edited on
If I change the ObtainRequests function and create an object that points to the newly created reqNode after I've modified it, and use that in line 28 of the function, would that bypass the issue?
Edit: The answer is no. Doing so routes me back to an error at line 13 in the ObtainRequests function:
Error C2228 left of '.timestamp' must have class/struct/union
What exactly is the compiler not liking about the creation of this pointer?
Last edited on
If I change the ObtainRequests function and create an object that points to the newly created reqNode after I've modified it, and use that in line 28 of the function, would that bypass the issue?

That's what I did in the code I mentioned

 
requests.InsertBack(&newnode);

Here &newnode creates a pointer (i.e. an object) that points to newnode.

What you could do is create the reqNode with malloc (or new). Then it will no longer get destroyed automatically. Instead it will be destroyed when you use free (or delete if you used new to create the object). In other words, every time you remove an element from the linked list you would have to remember to use free (or delete) otherwise you'll have a "memory leak". This is something you should do from outside the linked list class template because it is the user of the linked list that decided he wanted to store pointers to "dynamically allocated objects".

Smart pointers such as std::unique_ptr can help with this but it doesn't work well with malloc, and if your professor wants you to use malloc I doubt he wants you to use smart pointers. Note that malloc is quite rare to see in modern C++ code. It's more of a C thing. malloc and free do not call constructors and destructors like new and delete do.
Last edited on
Error C2228 left of '.timestamp' must have class/struct/union
What exactly is the compiler not liking about the creation of this pointer?

If newnode is a pointer to a reqNode (reqNode*) then you need to dereference the pointer to access the object that the pointer points to.

The dereference operator is *

 
(*newnode).timestamp = ...

Wanting to access a member of an object being pointed to by a pointer is quite common so there is actually a shorthand syntax to make it easier. Instead of writing (*p).m you can write p->m.

 
newnode->timestamp = ...
Last edited on
It's always useful to post a full example that should compile/show the error etc. Then we can simply just load the code into a compiler and see the issue/change the code to fix the issue(s).
As a starter code that compiles, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <string>
#include <new>

enum Status {NONE, GOLD, SILVER, PLATINUM};

struct reqNode {
	int         timestamp {};
	std::string name;
	Status      status {};
	int         duration {};
};

std::ostream& operator<<(std::ostream& os, const reqNode& n) {
	return os << n.name << "  " << n.status << "  " << n.timestamp << "  " << n.duration;
}

template <typename T>
class Dlist {
	struct node {
		T o {};
		node* prev {};
		node* next {};

		node(const T& o_) : o(o_) {}
	};

	node *first {}, *last {};

public:
	Dlist() {}

	~Dlist() {
		while (first) {
			const auto nxt { first->next };

			delete first;
			first = nxt;
		}
	}

	bool IsEmpty() const {
		return first == nullptr;
	}

	Dlist(const Dlist&) = delete;
	Dlist& operator=(const Dlist&) = delete;

	void InsertBack(const T& o) {
		const auto newnode { new (std::nothrow) node(o) };

		if (!newnode) {
			std::cout << "Overflow detected\n";
			return;
		}

		if (IsEmpty())
			first = newnode;
		else {
			last->next = newnode;
			newnode->prev = last;
		}

		last = newnode;
	}

	void display() const {
		for (auto n { first }; n; n = n->next)
			std::cout << n->o << '\n';

		std::cout << '\n';

		for (auto n { last }; n; n = n->prev)
			std::cout << n->o << '\n';

		std::cout << '\n';
	}
};

void ObtainRequests(Dlist<reqNode>& requests) {
	unsigned node_count {};

	std::cout << "How many nodes to insert: ";

	std::cin >> node_count;

	for (unsigned i {}; i < node_count; ++i) {
		std::string temp;
		reqNode newnode;

		std::cout << "Enter time (int), name (no spaces), status (regular, silver, gold, platinum), duration (int): ";
		std::cin >> newnode.timestamp >> newnode.name >> temp >> newnode.duration;

		if (temp == "regular")
			newnode.status = NONE;
		else if (temp == "silver")
			newnode.status = SILVER;
		else if (temp == "gold")
			newnode.status = GOLD;
		else
			newnode.status = PLATINUM;

		requests.InsertBack(newnode);
	}
}

int main() {
	Dlist<reqNode> ll;

	ObtainRequests(ll);

	ll.display();
}



How many nodes to insert: 2
Enter time (int), name (no spaces), status (regular, silver, gold, platinum), duration (int): 123 qwe silver 34
Enter time (int), name (no spaces), status (regular, silver, gold, platinum), duration (int): 234 asd regular 45
qwe  2  123  34
asd  0  234  45

asd  0  234  45
qwe  2  123  34

Topic archived. No new replies allowed.