std::declval 元函数
declval用于非求值上下文中
declval 原形:
template<typename _Tp>
auto declval() noexcept -> decltype(__declval<_Tp>(0))
{
static_assert(__declval_protector<_Tp>::__stop,
"declval() must not be used!");
return __declval<_Tp>(0);
}
.....
template<typename _Tp>
struct __declval_protector
{
static const bool __stop = false;
};
....
template<typename _Tp, typename _Up = _Tp&&>
_Up
//因为传的是0(int类型),所以可引用的类型始终决策出这个版本(编译时多态)
__declval(int);//利用SFINAE 使编译器能决策出最适合的版本
template<typename _Tp>//void等不可引用的类型始终决策出这个版本
_Tp
__declval(long);//利用SFINAE 使编译器能决策出最适合的版本
- __declval只有声明,没有定义;所以说用于求值上下文中会在链接时报错
所以上面用了静态断言以提供更友好的错误信息; - __declval_protector 延迟实例化时机 用于防止无条件编译错误
- 而在非求值上下文中使用时,不会对函数体内的语句进行检查,即不会执行静态断言,据此约束了使用场景;
- ! 利用了函数返回值的特性, 对于__declval你传什么类型就返回什么类型的"实体", 注意:这种实例化并不是真正的在内存上构造出对象, 它在编译期非求值上下文中,仅仅是用于构造合法的语句
- 注意返回类型不能写decltype(auto),虽然那样编译器也能推导出类型为decltype(__declval<_Tp>(0)); 但也意味着编译器需要看到函数体, 将触发函数体内的静态断言
用法1:求函数返回类型:
void commonF(int,double,char){};
template<class F,class... Args>//F:可调用对象 类型; Args:F的参数类型
using InvokeResultOfFunc =
decltype(declval<F>()(declval<Args>()...));
int main(){
//不仅可以用于普通函数, 还可用于函数对象的求返回类型
InvokeResultOfFunc<float (int), int> a{};//a为float类型
InvokeResultOfFunc<decltype(commonF), int,double,char> *b{};
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现