Глядя на исходный код libstdc++, я нашел следующую declval
реализацию:
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));
Эта реализация была предложена Эриком Ниблером в качестве оптимизации времени компиляции: он объясняет, что перегрузка разрешение быстрее, чем создание экземпляра шаблона.
Однако я не могу понять, как это работает. Конкретно:
- В (1), почему использование
_Up
лучше, чем просто возврат_Tp&&
? - Кажется, что перегрузка (2) никогда не используется. Зачем это нужно?
Как все это мешает инстанцированию шаблонов, в отличие от самой наивной реализации:
template<typename T>
T&& declval() noexcept;