Let the return type of a function auto foo(T f) be the same as when calling sin(f) from header cmath in cases where f is an intrinsic datatype:
template <typename T>
auto foo(T f) -> decltype(sin(f))
{
using std::sin;
return sin(f);
}
This is broken. The sin(f) within decltype is not looked up within std, hence only the C variant sin(double) is found, whose return type is double. The following program demonstrates that:
d
d
N3meh15SinfulNanometerE
d
f
N3meh15SinfulNanometerE
The output suggests that the return type is always double for foo->floatandfoo->double, only withinfoo(), the correct sin(float|double) is found because of the using std::sin, which imports all overloads.
I wonder if such case was taken into consideration in the gremium already, but that's not my question.
Question
My question is:
What is a sensible way to let foo have the same return-type as a function whose name is either in namespace std or ADL-looked-up?
Non working workaround:
template <typename T>
auto foo(T f) -> decltype(std::sin(f)); // Will miss sin(Nanometer)
Standard proposal?
template <typename T>
auto foo(T f) -> decltype(using std::sin; sin(f));
Using permutations of enable_if is in the way of code being self-documenting. enable_if is a nice exercise of metaprogramming. But to get a quick grasp of a seemingly simple function, imho not the right thing, therefore not in the spirit of maintainability.
edit: I am also using decltype to use SFINAE less obscurely, so C++14 with it's new auto foo() {....} declarations might not be of help.
해결책
You can use a detail namespace and some wrapping:
namespace detail {
using std::sin;
template<typename T>
auto foo(T f) -> decltype(sin(f)) { return sin(f); }
}
template<typename T>
auto foo(T f) -> decltype(detail::foo(f)) { return detail::foo(f); }
다른 팁
You need one level of indirection:
namespace find_sin
{
using std::sin;
template<typename T>
using type = decltype(sin(std::declval<T>()));
}
template <typename T>
find_sin::type<T> foo(T f)
{
// ...
}