Reputation: 91
#include <iostream>
using namespace std;
template <class X, class Y>
Y big(X a, Y b)
{
if (a > b)
return (a);
else return (b);
}
int main()
{
cout << big(32.8, 9);
}
Here I am using templates in CPP, so when I call the function big
bypassing arguments of double
and int
type, I want the return answer which is double
. The type here, it returns 32
instead of 32.8
.
How I get my desired output?
How to write a proper return type of big
function?
Upvotes: 9
Views: 440
Reputation: 5202
In marking your return type as Y
and passing an int
as your second parameter, you've clearly indicated that Y
is an int
. There's no surprises going on here.
#include <iostream>
template <typename X, typename Y>
decltype(auto) big(const X& a, const Y& b) // return type can just be auto as well
{
return a > b ? a : b;
}
int main()
{
std::cout << big(32.8, 9) << '\n';
std::cout << big(9, 32.8) << '\n';
std::cout << big(32.8, 90) << '\n';
std::cout << big(90, 32.8) << '\n';
}
This prints all four correct values to the screen.
One thing that's important to note is that this will only work for types that can be compared against each other, i.e., the compiler will implicitly convert one type to the other for the comparison.
IMPORTANT: The parameters need to be taken by reference to avoid undefined behavior. This has to do with the return type I am stubbornly sticking by. decltype(auto)
can return references to types. If you return something local to the function (arguments count), you get undefined behavior.
Upvotes: 4
Reputation: 32797
The return type must be determined at compile-time. You can use trailing return with a conditional operator, if you are limited to c++11.
template <typename X, typename Y>
auto big(X&& a, Y&& b) -> decltype(a > b ? a : b) // ---> like this
{
return a > b ? a : b;
}
However, if you have access to c++14 or higher auto
return is enough, as the compiler will deduce the right type if you use it along with the conditional operator as follows:
template <typename X, typename Y>
auto big(X a, Y b)
{
return a > b ? a : b;
}
Upvotes: 10
Reputation: 3938
This is not the correct solution for your precise situation, in all likelihood – the other answers are likely to be much closer to what you want.
However, if you really need to return entirely different types at runtime for some reason, the correct solution (since c++17) is to use a std::variant
, which is a sort of type-safe union.
#include <variant>
template <typename X, typename Y>
std::variant<X, Y> max(X a, Y b) {
if (a > b)
return std::variant<X, Y>(std::in_place_index_t<0>, a);
else
return std::variant<X, Y>(std::in_place_index_t<1>, b);
}
Note that then the onus is on the caller to deal with the returned value, most likely using std::visit
or the like.
Upvotes: 3
Reputation: 1
It returns int because Y is an int and it casts the 32.8 to it. When you called big 32,82 is a float, but 8 is an int and the function return type is Y, which is also int.
You can't really fix this as you need to know at runtime which type big returns, so make a and b the same type like this:
#include <iostream>
using namespace std;
template <typename X>
X big (X a, X b)
{
if (a>b)
return a;
else return b;
}
int main()
{
cout<< big (32.8, 9.0);
}
Upvotes: -2
Reputation: 122458
A function can have only one return type that has to be known at compile time. However, you can use std::common_type
, to return a type that both parameters can be implicity converted to.
That would be
#include <type_traits>
template <class X, class Y>
typename std::common_type<X,Y>::type big(X a, Y b)
{
if (a > b)
return a;
else return b;
}
And to check that it actually returns a double
when passed an int
and a double
we can do:
int main() {
auto x = big(4.2,42);
std::cout << std::is_same<decltype(x),double>::value;
}
Which prints
1
PS: std::common_type
can use the ternary operator behind the scences and as such this solution isnt much different from the other answers (auto
+ ternary). The real power of std::common_type
is that it accepts any number of parameters.
Upvotes: 12