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.
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.
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?
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.
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.
Related
In the below code example, the second line
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4);
causes compiler failures because no proper substitution is found.
If there is an error, then how is this SFINAE? I thought std::enable_if is kind of SFINAE and the acronym means no failure if substitution can't be done. Where I am misinterpreting?
#include <iostream>
#include <type_traits>
template<class T, class = std::enable_if_t<std::is_integral_v<T>>>
bool is_even(T value)
{
return ((value % 2) == 0);
}
int main()
{
std::cout << "is_even (4) = " << std::boolalpha << is_even(4);
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4);
}
Please don't say what i expect in this situation to happen. I am just trying to see how should i see SFINAE here?
The error is caused by the call expression is_even(4.4). Since you have called a function is_even by passing a double, the definition of such a function must exist.
If we call any function, then its definition must exist somewhere. In your case, there is no function named is_even that takes a double parameter and hence the error.
SFINAE still works here. For example, when the template argument is deduced to be a double and then T is substituted with double the condition inside std::enable_if_t<std::is_integral_v<T>> evaluates to false. Thus this function template is ignored and no error is produced at this point. That is, the error that you're getting is not due to SFINAE. SFINAE doesn't mean that your program won't produce any error.
Now, for the call expression is_even(4.4) to work the compiler can't find any is_even that takes a double. And so it produced error. You can confirm this by overloading this function template with an ordinary function as shown below:
template<class T, class = std::enable_if_t<std::is_integral_v<T>>>
bool is_even(T value)
{
return ((value % 2) == 0);
}
//compiler will find this definition now and no error will be produced
bool is_even(double d)
{
return ((static_cast<int>(d) % 2) == 0);
}
Now for the call expression is_even(4.4) the compiler finds the overloaded is_even and hence produces no error.
Summary
The error that you're getting is not the result of SFINAE, instead it is due to the fact that the for the expression is_even(4.4) to work, we need the definition of a function that takes a double.
In the following code
#include<iostream>
template<typename T,size_t N>
void cal_size(T (&a)[N])
{
std::cout<<"size of array is: "<<N<<std::endl;
}
int main()
{
int a[]={1,2,3,4,5,6};
int b[]={1};
cal_size(a);
cal_size(b);
}
As expected the size of both the arrays gets printed. But how does N automatically gets initialized to the correct value of the array-size (arrays are being passed by reference)? How is the above code working?
N does not get "initialized" to anything. It is not a variable. It is not an object. N is a compile-time constant. N only exists during compilation. The value of N as well as the actual T is determined by the process called template argument deduction. Both T and N are deduced from the actual type of the argument you pass to your template function.
In the first call the argument type is int[6], so the compiler deduces that T == int and N == 6, generates a separate function for that and calls it. Let's name it cal_size_int_6
void cal_size_int_6(int (&a)[6])
{
std::cout << "size of array is: " << 6 << std::endl;
}
Note that there's no T and no N in this function anymore. Both were replaced by their actual deduced values at compile time.
In the first call the argument type is int[1], so the compiler deduces that T == int and N == 1, generates a separate function for that as well and calls it. Let's name it cal_size_int_1
void cal_size_int_1(int (&a)[1])
{
std::cout << "size of array is: " << 1 << std::endl;
}
Same thing here.
Your main essentially translates into
int main()
{
int a[]={1,2,3,4,5,6};
int b[]={1};
cal_size_int_6(a);
cal_size_int_1(b);
}
In other words, your cal_size template gives birth to two different functions (so called specializations of the original template), each with different values of N (and T) hardcoded into the body. That's how templates work in C++.
It works because the type of a is "array of length 6 of int" and the type of b is "array of length 1 of int". The compiler knows this, so it can call the correct function. In particular, the first call calls the template instance cal_size<6>() and the second call calls cal_size<1>(), since those are the only template instantiations which match their respective arguments.
If you attempted to call an explicit template instance, it would only work if you got the size right, otherwise the arguments wouldn't match. Consider the following:
cal_size(a); // ok, compiler figures out implicitly that N=6
cal_size<int, 6>(a); // also ok, same result as above
cal_size<int, 5>(a); // ERROR: a is not of type "array of length 5 of int"
when you declare int a[] = {1,2,3} it is the same as (or will be rewritten as) int a[3] = {1,2,3} since the templated function is receiving argument in form of T a[N], then N will have value of 3.
I'm trying to understand universal references and std::enable_if better, but I'm a little stuck as to what's going on here in my code.
First off, I've noticed people seem to use std::enable_if in two different ways:
template<typename T, std::enable_if<condition, T>::type* = nullptr> or something similar to that.
template<typename T> std::enable_if_t<condition, T> myfunc() {...} or something similar to that.
I understand what's happening in the second, but I'm confused about why anyone would use the first. What does that achieve except add another parameter to the template? Is it an SFINAE thing?
I'm also stuck on universal references when using enable_if. Here is my code and the results I'm getting. Note that I'm using Howard Hinnant's type printing code from "Is it possible to print a variable's type in standard C++?", which I'll omit here for brevity.
Anyways, the function conditionless seems to work fine with everything.
I'm very confused about is_integral and decay, which you can see at thhe beginning of main. I get the output:
true: unsigned long
false: unsigned long
false: unsigned long
false: unsigned long
and I have no idea why the last three are false.
Then I have the issues (marked 1 and 2 in the source below) where when using enable_if in either of the two ways mentioned above, they refuse to compile when accepting an lvalue of an integral or floating point type.
Headers and type printing code omitted for brevity:
template<typename T>
void conditionless(T&& val) {
std::cout << "conditionless(" << val << ")\n";
}
template<typename T, typename std::enable_if<std::is_integral_v<T>, T>::type* = nullptr>
void outputIntType(T&& val) {
std::cout << "outputIntType(" << val << ")\n";
}
template<typename T>
typename std::enable_if_t<std::is_floating_point_v<T>>
outputFloatType(T&& val) {
std::cout << "outputFloatType(" << val << ")\n";
}
int main() {
size_t sz = 1;
size_t &ref = sz;
// All of these report as having type "unsigned long", but for some reason, the first reports true for is_integral, and
// the other three report false.
std::cout << std::boolalpha << std::is_integral_v<decltype(sz)> << ": " << type_name<decltype(sz)>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<std::decay<decltype(sz)>> << ": " << type_name<std::decay<decltype(sz)>::type>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<decltype(ref)> << ": " << type_name<decltype(sz)>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<std::decay<decltype(ref)>> << ": " << type_name<std::decay<decltype(ref)>::type>() <<'\n';
// This works fine.
conditionless(sz);
conditionless(2UL);
conditionless(2L + 1);
// ******* 1 *******
// This fails and claims no matching function call to outputIntType(size_t&)
// template argument deduction / substitution failed:
// error: no type named 'type' in 'struct std::enable_if<false, long unisgned int&>'
// I'm particularly confused about why the is_integral evaluates to false.
//outputIntType(sz);
// These work fine.
outputIntType(2UL);
outputIntType(2L + 1);
double pi = 3.1415926535;
// These work fine.
conditionless(pi);
conditionless(2 * pi);
conditionless(0.00000001);
// ******* 2 *******
// This fails as well:
// main.cpp: In function 'int main()':
// error: no matching function for call to 'outputFloatType(double&)'
// note: candidate: 'template<class T> std::enable_if_t<is_floating_point_v<T> > outputFloatType(T&&)'
// template argument deduction/substitution failed:
// outputFloatType(pi);
// These work fine.
outputFloatType(2 * pi);
outputFloatType(0.00000001);
}
Any insight that anyone could give me on the two different uses of enable_if and why my code with enable_if refuses to accept lvalues would be greatly appreciated.
I'm trying to understand universal references
Use of that term is discouraged. The official term is "forwarding references".
I understand what's happening in the second, but I'm confused about why anyone would use the first. What does that achieve except add another parameter to the template? Is it an SFINAE thing?
All enable_if_t<B, T> does is evaluate to T if B == true, otherwise it produces invalid code. Invalid code produced during substitution doesn't lead to a compilation error (SFINAE).
It doesn't matter where enable_if_t appears as long as it's affected by the substitution step (e.g. can be in the return type, parameter list, template parameter list, ...).
and I have no idea why the last three are false.
You forgot to access ::type in your std::decay transformation. You are comparing the trait itself, not its result.
they refuse to compile when accepting an lvalue of an integral or floating point type.
There is a special rule regarding deduction of forwarding references in the Standard. Given a forwarding reference parameter T&&, T will be deduced as an lvalue reference if the function is called with an lvalue.
You need to take this into account in your traits:
typename std::enable_if_t<std::is_floating_point_v<std::remove_reference_t<T>>>
I am trying to use operator sizeof... to skip the function for the end of recursion by not calling it if there are no argument
#include<iostream>
template<typename T, typename ...Types>
void Display(T firstArg, Types...Args)
{
std::cout << firstArg << "\n";
std::cout << sizeof...(Types) << "\n";
std::cout << sizeof...(Args) << "\n";
if (sizeof...(Args) > 0)
Display(Args...);
}
int main()
{
Display(1, 2, 3,"hello");
return 0;
}
But I am getting following error for Display(Args...);
error C2780: 'void Display(T,Types...)': expects 2 arguments - 0
provided
Workaround is to add function for the end of recursion (which I want to avoid)
void Display()
{
}
Question is how to avoid end of recursion function
You can’t do this without some workaround, pre-C++17, unless you rewrite the function to not be recursive. The reason is that the entire function body is substituted, including branches of if statements that can never happen. That means that the compiler sees the call to Display() with no arguments, even though it would never have happened at runtime.
Since C++17, the solution to this is to use if constexpr instead of just if. That tells the compiler to evaluate the condition at compile time, and not try to compile the branch which doesn’t execute.
Note that “not try to compile” above is a simplification; the link has more details about what exactly is and isn’t done.
In c++ (GNU GCC g++), my code is "calling" a function without ().
The function is not working, but compiles ok.
More surprisingly, the code always returns 1...
Is there any explanation?
I expected the function name to be just a regular pointer, but seems it's a bit different...
Did I get all 1's only by chance?
#include <iostream>
using namespace std;
void pr ()
{
cout << "sth";
}
int main()
{
pr;
cout << pr; // output: 1
cout << *pr; // output: 1
cout << ≺ // output: 1
}
You're not actually calling pr in your code, you're passing the function pointer to cout. pr is then being converted to a bool when being passed to cout. If you put cout << boolalpha beforehand you will output true instead of 1.
EDIT:
With C++11 you can write the following overload:
template <class RType, class ... ArgTypes>
std::ostream & operator<<(std::ostream & s, RType(*func)(ArgTypes...))
{
return s << "(func_ptr=" << (void*)func << ")(num_args="
<< sizeof...(ArgTypes) << ")";
}
which means the call cout << pr will print (func_ptr=<address of pr>)(num_args=0). The function itself can do whatever you want obviously, this is just to demonstrate that with C++11's variadic templates, you can match function pointers of arbitrary arity. This still won't work for overloaded functions and function templates without specifying which overload you want (usually via a cast).
The name of a function, when used without parentheses, can be implicitly cast to a function pointer. In fact, when you dereference or reference it, it remains nothing but a function pointer, or a poointer to a function pointer, etc. These function pointers, when printed, are implicitly cast to bool, which is why they simply output 1. If you want to output the actual memory address of the function, cast it to a void pointer:
cout<<(void*)pr;