I'm writing this code
#include <iostream>
#include <string>
template <typename T>
void Print(T& value)
{
std::cout << value << std::endl;
}
int main()
{
Print("Hello");
Print(1);
}
And when compiling, compilers told an error that “void Print<int>(T &)' : cannot convert argument 1 from 'int' to 'T &'". But the Print("Hello") didn't get an error. Why is that?
And I changed Print() function to
void Print(T value)
{
std::cout << value << std::endl;
}
It worked. But I don't understand why the former code didn't work.
CodePudding user response:
Case 1
Here we consider how Print(1); works.
In this case, the problem is that 1 is an rvalue and you're trying to bind that rvalue to a lvalue reference to nonconst T( that is, T&) which is not possible and hence the error. For example you cannot have:
void Print(int &value)
{
std::cout << value << std::endl;
}
int main()
{
Print(1);// won't work
}
Solution
So to solve your problem you can use a lvalue reference to const T(that is const T&) that can be bind to an rvalue, as shown below:
template <typename T>
void Print(const T& value)//note the const added here
{
std::cout << value << std::endl;
}
int main()
{
Print(1); //works now
}
Alternatively, you can also make the parameter as a rvalue reference to nonconst T(that is T&&).
template <typename T>
void Print(T&& value)//note the && added here
{
std::cout << value << std::endl;
}
int main()
{
Print(1); //this works too
}
Case 2
Here we consider the statement Print("Hello");
In this case, "Hello" is a string literal and has the type const char [6]. Also, the string literal "Hello" is an lvalue.
And we know that we can bind an lvalue to a lvalue reference to nonconst T(that is T&). So there is no error in this case. Also note that in this case the T is deduced to be const char [6].
Note
In case 2 above (Print("Hello");) there is no type decay because the argument is passed by reference and not by value.
CodePudding user response:
Because of this:
test.cpp:45:11: error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
45 | Print(1);
| ^
So convert it to a universal reference:
template <typename T>
void Print( T&& value ) // notice &&, that's a universal reference, not an rvalue ref
{
std::cout << value << std::endl;
}
CodePudding user response:
1 is an rvalue, and so cannot bind to T&. It can bind to const T& though.
That is,
void Print(const T& value)
or
void Print(T&& value)
are the fixes.
