Reputation: 151
I rarely use templates. I don't know why I see a build error in the below code for the push
method of Node<float>
Build Error is: No matching function to call push.
Node<int>*
push method is fine though.
Node<float>* head1 = NULL;
push(&head1, 1);
template <typename T>
struct Node {
T data;
Node* next;
};
template <typename T>
void push(Node<T>** head, T data) {
Node<T>* tmp = *head;
Node<T>* newNode = NULL; //createNode(data);
if (tmp == NULL) {
*head = newNode;
}
else {
while (tmp->next)
tmp=tmp->next;
tmp->next = newNode;
}
}
int main(int argc, const char * argv[]) {
Node<float>* head1 = NULL;
push(&head1, 1);
Node<int>* head = NULL;
push(&head, 1);
return 0;
}
Upvotes: 15
Views: 1579
Reputation: 4283
Another alternative is to use a second typename parameter on the push template:
template <typename T, typename U>
void push(Node<T>** head, U data) {
...
}
It deduce T to float and U to int and it works because the it applies floating-integer conversion.
Also you can add std::is_assignable<T,U>
to the template, but is quite a pain to use it.
Upvotes: 0
Reputation: 24269
The problem is that in the float case T data
is deduced to be of type float
, but you pass it an integer value:
template <typename T>
void push(Node<T>** head, T data)
--^
push(&head1, 1);
+--^ ^-- int
^ Node<float>*
If you change this to
push(&head1, 1.0f);
it works: http://ideone.com/hxaDZ5
Upvotes: 1
Reputation: 275740
The C++ compiler treats all function arguments symmetrically. Every one is equally important.
template <typename T>
void push(Node<T>** head, T data)
here we have two arguments. When we call push
without explicitly passing it T
, we deduce T
from the arguments.
If you pass it a pointer to a pointer to a Node<float>
and an int
, the compiler gets confused. Is T
a float
, or an int
?
While you could solve it, and we could modify C++ to solve it, the result could easily be surprising. So instead, C++ says "types deduced are not consistent".
We can fix this in a number of ways.
You could pass a float
for data
. push(&head, 0.1f)
or push(&head, float(1))
or whatever.
You can pass the type T
explicitly: push<float>(&head, 1.0)
.
You can block deduction for the 2nd argument. This means that T
gets deduced from the first argument, and never from the 2nd:
template<class T>struct block {using type=T;};
template<class T>using block_deduction = typename block<T>::type;
template <typename T>
void push(Node<T>** head, block_deduction<T> data)
You can realize we don't care what the second arguments type is, and leave it free:
template <typename T, typename U>
void push(Node<T>** head, U data)
You can replace push
with a more modern emplace
that has you pass construction arguments for your T
instead of a T
directly. As copy constructors mean that a variable of type T
is valid, this is a drop-in replacement usually:
template <typename T, typename...Args
void emplace(Node<T>** head, Args&&...args) {
Node<T>* tmp = *head;
Node<T>* newNode = new Node<T>(std::forward<Args>(args)...);
// ...
This is the turbo-charged version. It lets you create Node<non_movable_type>
, and it can lead to efficiencies in other cases, such as types that are cheap to construct but expensive to move around.
All of the above are reasonable solutions, but I find the first two poor, as they leave your interface brittle.
Upvotes: 1
Reputation: 217810
As alternative, you may do the second argument non deducible:
template <typename T> struct non_deducible
{
using type = T;
};
template <typename T> using non_deducible_t = non_deducible<T>::type
template <typename T>
void push(Node<T>** head, non_deducible_t<T> data)
Upvotes: 7
Reputation: 172964
For push(&head1, 1);
, the type of &head1
is Node<float>**
, and type of 1
is int
, then type deduction for template parameter T
will fail with conflicting types (float
vs. int
).
You could make the types match:
push(&head1, 1.0f);
or explicitly specify the template argument by float
, and 1
will be casted to float
.
push<float>(&head1, 1);
Upvotes: 21
Reputation: 126
you could try:
Node<float>* head1 = NULL;
push(&head1, float(1));
Upvotes: 0