Reputation: 15175
I am trying to write a simple function that will get me a number from user input within a range.
When instanciating this function i explicitly tell it i want it instanciated with int
but still i get the error:
thermo.cpp:105:31: error: no matching function for call to ‘getInput(int&)’
Why is is trying to find a function that takes int&
as argument?
template<class T, T min = std::numeric_limits<T>::min, T max = std::numeric_limits<T>::max>
T getInput(T default_value = T()){
std::string input;
T myNumber = T(); //default inits
while(true){
getline(cin, input);
if(input.length() == 0){
return default_value;
}
// This code converts from string to number safely.
stringstream myStream(input);
if (myStream >> myNumber){
if(myNumber > max || myNumber < min){
stringstream ss;
ss << "Input out of bounds. Received " << myNumber << " expected between " << min << " and " << max << ".";
throw invalid_argument(ss.str());
}
return myNumber;
}
cout << "Invalid number, please try again" << endl;
}
}
void get(const std::string& prompt, int& param){
cout << prompt << " [" << param << "]:";
param = getInput<int,0>(param); // i specifically tell it i want 'int', why am i getting 'int&'?
}
Update
If i try CharlesB suggestion:
void get(const std::string& prompt, int& param){
cout << prompt << " [" << param << "]:";
param = getInput<int,0>(int(param));
}
i get
thermo.cpp:105:36: error: no matching function for call to ‘getInput(int)’
Forgot:
g++ 4.5.3 under cygwin
Command line:
$ g++ thermo.cpp -o thermo.exe -Wall -pedantic -std=c++0x
Update 2
if i call it like this
void get(const std::string& prompt, int& param){
cout << prompt << " [" << param << "]:";
param = getInput<int,0,15>(int(param)); // fully parameterized
}
it works... but i'd rather not specify an upper bound (not even numeric_limits
) on each call.
Upvotes: 2
Views: 261
Reputation: 208333
The error code does not mean what you think. The error code is a shorthand for:
no matching function call to getInput
that takes an int
modifiable lvalue expression as the single argument
Where int
modifiable lvalue expression is the type of the expression that you are using to make the call in this case param
. Now the problem is that output of error codes in this format is that it is very verbose and it would become very hard to read with just two or three arguments of non trivial types, so the compiler condenses the error report and tells you:
no matching function call to getInput(int&)
, note that here int&
is not the type of the function that will be called, as the compiler was unable to find such a function, but rather it is the type of the argument that is being used in the call.
If you perform the change that CharlesB suggests, then you will get a different error message saying that it cannot find getInput(int)
. The difference here is that int(param)
creates a temporary (rvalue expression), so the error now reflects it. The need for a different error code comes from the fact that if you had a getInput(int&)
function, in this second case, that overload cannot be used.
On the reason why you are getting that error code the basic problem is that std::numeric_limits<T>::max
is not of type T
. Your problem is the very base of SFINAE: You have defined a template that takes as second and third arguments T
, and that T
should be initialized with std::numeric_limits<T>::min
(and max
). Now when the compiler tries to determine the function to call, it will find that template, use T
for int
(you provided the exact type), 0
for the min and will then try to infer the last argument. At this point it will try to get a T
value (last template argument) through the default template argument by substituting the known template arguments in: std::numeric_limits<T>::max
. The problem is that std::numeric_limits<int>::max
is not an int
, but rather a static member function, so the types don't match, yielding a substitution failure. The language determins that substitution failure is not an error (SFINAE) and it only means that this template will be removed from the list of candidates for the function call. Because there is no other matching overload, the compiler gives up and tells you that it could not find a matching function for the call.
In C++11 you can use std::numeric_limits<T>::max()
, as the function is marked as a const_expr
and can thus be called to obtain a constant expression of type T
that can be used as the template argument, but if you are working with a C++03 compiler, you will need to work around the problem in a different way, like moving the min
and max
to default arguments to a function, or providing different overloads that take values from the user or will call a function (default to std::numeric_limist<T>::max
if the argument is not present, but this latter option is more cumbersome.
Upvotes: 2
Reputation: 21900
Don't use templates for min
and max
:
template<class T>
T getInput(T default_value = T(), T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max());
There is no reason to use templates for those arguments(besides the fact that it does not work).
Edit: You can't use those arguments as template values since std::numeric_limits<T>::min()
is a function, its value is known on runtime, and template value arguments have to be bound to a value at compile time. This is valid:
template<class T, T min = 0, T max = 5>
T getInput(T default_value);
Since 0 and 5 are known during compilation.
Upvotes: 3
Reputation: 37453
I don't know if this is the issue, but I can't imagine it's helping. This line:
template<class T, T min = std::numeric_limits<T>::min, T max = std::numeric_limits<T>::max>
...is using min/max as values, when they're really functions. Maybe that's confusing the template parameters?
Upvotes: 2
Reputation: 90316
Template functions are instanciated with argument type, and param
is a int&
.
Rather do
param = getInput(int(param));
Also min and max can't be template arguments, a template argument is class, a typename or a POD.
Upvotes: 1