查看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));
埃里克·尼伯勒(Eric Niebler(提出了这种实现作为编译时间优化:他解释说,超载分辨率比模板实例化快。
但是,我不明白它是如何工作的。具体:
- 在(1(中,为什么使用
_Up
远胜于返回_Tp&&
? - 似乎从未使用过超载(2(。为什么需要?
所有这些如何防止模板实例化,而不是最幼稚的实现:
template<typename T>
T&& declval() noexcept;
幼稚的实现不是完全正确的。根据标准,declval
定义为([dectval](:
template <class T> add_rvalue_reference_t<T> declval() noexcept;
和add_rvalue_reference<T>
标准读取([meta.trans.ref](:
如果
T
名称为引用类型,则成员Typedeftype
名称T&&
;否则,type
名称T
。
不可推荐类型的示例是void
。借助Sfinae,在这种情况下将使用第二个过载。
关于第一个问题,我没有看到任何特殊原因。_Tp&&
应该正常工作。