You are getting an error because return types are not deduced during template argument deduction. Instead they are substituted from the deduced function arguments. Because both overloads have the same arguments deduced, overload resoution is ambiguous which gives a compiler error.
In C++11 you can define a default template parameter for function templates. If you add an extra default function parameter equal to the default return value, you will always get the argument type as return type, unless you explicitly pass a default return value:
#include <iostream>
#include <cmath>
#include <type_traits>
template <typename T, typename Ret = T>
Ret xround(T val, Ret ret = Ret()) {
return static_cast<Ret>(
(val >= 0) ?
floor(val + (T)(.5)) :
ceil( val - (T)(.5))
);
}
int main()
{
auto a = xround(5.5, int()); // = 6
static_assert(std::is_same<decltype(a), int>::value, "");
std::cout << a << "\n";
auto b = xround(5.5); // = 6.0
static_assert(std::is_same<decltype(b), double>::value, "");
std::cout << b << "\n";
}
Note that I used the ternary operator instead of your if-else
, and that I renamed the function to xround
because in C++11 there already is a round
inside <cmath>
(which of course you could also use).
Note: the temporary is similar to tag dispatching: it is entirely used to determine the return type and the actual temporary should be optimized away by the compiler.