Looking at libstdc++ source code, I found the following declval
implementation:
template<typename _Tp, typename _Up = _Tp&&>
_Up __declval(int); // (1)
template<typename _Tp>
_Tp __declval(long); // (2)
template<typename _Tp>
auto declval() noexcept -> decltype(__declval<_Tp>(0));
This implementation was proposed by Eric Niebler as a compile time optimization: he explains that overload resolution is faster than template instantiation.
However, I can't understand how it works. Specifically:
- In (1), why is using
_Up
better than just returning_Tp&&
? - It seems that the overload (2) is never used. Why is it needed?
How all this prevents template instantiations, as opposed to the most naive implementation:
template<typename T>
T&& declval() noexcept;