Compiler error with std::enable_if when substitution fails - c++

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.

Related

Differences in uses of std::enable_if and universal references

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>>>

Use of sizeof operator in Variadic Template to skip the function for the end of recursion

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.

auto Function with if Statement won't return a value

I made a template and an auto function that compare 2 values and return the smallest one.
This is my code:
#include <iostream>
using namespace std;
// Template with a value returning function: PrintSmaller
template <typename T, typename U>
auto PrintSmaller(T NumOne, U NumTwo) {
if (NumOne > NumTwo) {
return NumTwo;
}
else {
return NumOne;
}
}
int main() {
int iA = 345;
float fB = 23.4243;
cout << PrintSmaller(iA, fB) << endl;
cout << PrintSmaller(fB, iA) << endl;
return 0;
}
But it won't compile, I get this error on VS 2015:
Error C3487 'int': all return expressions must deduce to the same type: previously it was 'float'
However, if I delete the if statement and write the function PrintSmaller like this it works with no problems :
auto PrintSmaller(T NumOne, U NumTwo) {
return (NumOne < NumTwo ? NumOne : NumTwo);
}
What is the difference ? and why the first code won't compile ?
Thank you.
A function can only have a single return type. Using return type deduction means that it will be deduced based on the type of the expression in the first return statement the parser sees. If later return statements do not return expressions of the same type, then the function is considered to be self-contradictory and thus ill-formed.
In the second case, the ?: determines the type of the expression based on a common type determined based on the second and third sub-expressions. The two sub-expressions will be converted to this common type.
That's different from how return type deduction works. If you intend for your first case to work, then you need to explicitly convert the returned value to the desired return type.
As you have asked this question with the c++11 marker, I suppose you are using C++11. Unfortunately, the C++11 standard states that auto-type deduction (also for lambdas) is limited to a single statement.
As the ?: operator is an expression instead of a statement, this will work while the if-else is a statement and doesn't meet the requirements.
If you would compile this code with the C++14 standard, you will see that it should compile both cases as this limitation was removed.
Until yesterday (2017-12-06) this was not compiling under MSVC. But after VS 15.5 update it does.
auto msvc_does_compile = [](auto _string)
{
using string_type = decltype(_string);
return std::vector<string_type>{};
};
/*
OK since VS 2017 15.5 update
auto vec1 = msvc_does_compile( std::string{} );
*/
Adding explicit return type will choke MSVC , but not gcc/clang as usual:
auto msvc_does_not_compile = [](auto _string)
// explicit return type makes msvc not to compile
-> std::vector< decltype(_string) >
{
using string_type = decltype(_string);
return std::vector<string_type>{};
};
And something of the same but simpler will be stopped even at the IDE stage:
auto msvc_ide_does_not_allow = []( bool wide )
{
if (wide)
return std::vector<std::string>();
return std::vector<std::wstring>();
};
Yes, again that troublesome pair gcc/clang has no problems with the above. Try which ever online ide you prefer to convince yourself...

Why is the template trying to instanciate with 'int&' instead of 'int'?

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.

C++ : cout with a terenary if-statement

I get this ERROR: "error: overloaded function with no contextual type information".
cout << (i % 5 == 0) ? endl : "";
Is what I am doing possible; am I just doing it wrong, or do I have to overload the << operator?
It won't work that way (even if you fix the the precedence error). You have two problems here, the second more severe than the first.
The first problem is that std::endl is a template. It is a function template. A template has to be specialized. In order to specialize that template the compiler has to know (to deduce) the template arguments. When you do
std::cout << std::endl;
the specific function pointer type expected by operator << is what the compiler uses to figure out how to specialize the std::endl template.
However in your example you essentially "detached" the std::endl from operator << by moving the std::endl into an ?: subexpression. Now the compiler has to compile this expression first
(i % 5 == 0) ? endl : ""
This expression cannot be compiled since the compiler does not know how to specialize the std::endl template. There's no way to deduce the template arguments without any context.
For example, this simple C++ program
#include <iostream>
int main() {
std::endl;
}
will also fail to compile for the very same reason: without context the compiler does not know how to instantiate std::endl.
You can "help" the compiler to resolve the problem by specifying the template arguments explicitly
(i % 5 == 0) ? endl<char, char_traits<char> > : "";
This will explicitly tell compiler how to instantiate endl. The original error message you were getting will go away.
However, this will immediately reveal the second, more serious problem with that expression: specialized endl is a function (which decays to a function pointer in this context) while "" is a string literal. You cannot mix a function pointer and a string literal in a ?: operator like that. These types are incompatible. They cannot be used together as the 2nd and the 3rd operand of ternary ?:. The compiler will issue a different error message about this second problem.
So, basically, that latest problem you have here is as if you tried to do something like
cout << (i % 5 == 0 ? 10 : "Hi!");
This will not compile for the very same reason your expression will not compile.
So, the expression you are trying to write cannot be written that way. Rewrite it without trying to use the ?: operator.
As support, see the following transcript:
$ cat qq.cpp
#include <iostream>
using namespace std;
int main (void) {
int i = 5;
cout << ((i % 5 == 0) ? endl : "");
return 0;
}
$ g++ -o qq qq.cpp
qq.cpp: In function 'int main()':
qq.cpp:5: error: overloaded function with no contextual type information
The two arguments to the ? operator must be of the same type (at least after potential promotions, implicit constructors, casting operators etc. kick in). std::endl is actually a function template (details below) which the stream then invokes to affect its state: it is not a string literal like "".
So, you can't do this exactly, but you can probably get the behaviour you actually want - consider whether...
expr ? "\n" : ""
...meets your needs - it is similar but doesn't flush the stream (IMHO, std::cout should generally be flushed as infrequently as possible - especially by low level library code - as that provides better performance). (It's also more flexible, e.g. expr ? "whatever\n" : "" / can't append endl to a string literal.)
E.g. for GCC 4.5.2, endl is:
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }
The two alternatives of ?: must have the same type or one be convertible to the other.
endl is a template and the context doesn't give enough information for which to choose. So it hasn't even a type. (Thats is your error message).
As other already said, the binding isn't the one you expect.
It may well be possible (I doubt it myself). However, it's also silly, effectively as silly as:
cout << "";
What you should be doing in this case is a simple:
if (i % 5 == 0) cout << endl;
You shouldn't use ternary just for the sake of using it. Actually you shouldn't use any language feature just for the sake of using it. I don't write code like:
if (1) { doSomething(); }
just because I can. A simple doSomething(); is much better.
Try this, it works:
cout << ((i % 5 == 0) ? "\n" : "");
This is how it is supposed to look like to make it work correctly:
cout << ((i % 5 == 0) ? '\n' : " ");
Operator << has higher priority than ?:. Try this:
cout << ((i % 5 == 0) ? endl : "");