c++-----declval

news/2024/9/23 18:18:04

std::declval

基本概念和常规实例

std::decval–C++新标准中出现的函数模板,没有函数体(只有声明、没有实现),无法调用,一般用于与decltype,sizeof等关键字配合来进行类型推导、占用内存空间计算等

查看源码:

 add_rvalue_reference:是C++标准库中的类模板,他的能力是给进一个类型,它能够返回该类型的右值引用类型。

  1. 给进一个int类型,返回的是int&&

  2. 给进一个int&类型,返回的还是int&,这里用到引用折叠

  3. 给进一个int&&类型,返回的是int&&类型,依旧用到引用折叠

std::declval的功能:返回某个类型T的右值引用,不管该类型是否有默认构造函数或者该类型是否可以创建对象,返回某个类型T的右值引用,这个动作是在编译时完成的,所以很多人把std::declval也称为编译时工具

 

namespace nmsp1 {class A {public://构造函数A(int i) {printf("A::A()函数执行了,this=%p\n", this);}double myfunc() {printf("A::myfunc()函数执行了,this=%p", this);return 12.1;}};
}using YT = decltype(std::declval<nmsp1::A>());//这里注意不要把std::declval<nmsp1::A>后面的圆括号丢掉,否则代码含义发生变化//利用boost输出类型名比typeid(...).name()用法输出类型更准确
using boost::typeindex::type_id_with_cvr;
cout << "YT = " << type_id_with_cvr<YT>().pretty_name() << endl;//显示YT类型
//YT = class nmsp1::A &&

如果有需求需要得到myfunc的返回类型

  • 传统做法:必须创建一个对象
nmsp1::A myaobj(1);
using boost::typeindex::type_id_with_cvr;
cout << "myaobj.myfunc的返回类型 = " << type_id_with_cvr<decltype(myaobj.myfunc())>().pretty_name() << endl;
//A::A()函数执行了,this=003CF8C7
// myaobj.myfunc的返回类型 = double
//如果myfunc函数权限为私有,此时不可以获取
  • 不想创建对象获取到实际类型
using boost::typeindex::type_id_with_cvr;
cout << "A::myfunc的返回类型 = " << type_id_with_cvr<decltype(std::declval<nmsp1::A>().myfunc())>().pretty_name() << endl;
//A::myfunc的返回类型 = double

nmsp1::A&& ayinobj();//看起来是一个函数声明的语法,该函数返回的类型是A&&,可以看成返回一个A&&类型的对象,这种对象可以看成类A对象
//ayinobj();//看起来像调用ayinobj这个函数
//编译没错,链接不行
//ayinobj().myfunc();//同样纯编译没错

decltype(ayinobj().myfunc())  mydblvar;//定义一个double类型的变量mydblvar
//编译链接没错了

 

因为decltype推断类型时是不需要真的调用这个函数,也不需要调用A的myfunc,既然不需要调用,就没必要提供这种函数的函数体

sdt::declval

1.从类型转换的角度来说,将任意一个类型转换成右值引用类型

2.从假想创建出某类型对象的角度来说,配合decltype,令在decltype表达式中,不必经过该类型的构造函数就能使用该类型的成员函数

3.注意:std::declval不能调用,也不能创建任何对象,但std::declval能在不创建对象的情况下,达到创建了一个该类型对象的效果或者说程序员可以假定创建一个该类型的对象

 

std::declval为什么返回右值引用类型

  • 返回类型本身是不好的
namespace nmsp2 {template<typename T>T mydeclval()noexcept;  //这里返回T
}using boost::typeindex::type_id_with_cvr;
cout<<"mydeclval()的返回类型 = "<<type_id_with_cvr<decltype(nmsp2::mydeclval<nmsp1::A>())>().pretty_name() << endl;cout << "mydeclval().myfunc的返回类型 = " << type_id_with_cvr<decltype(nmsp2::mydeclval<nmsp1::A>().myfunc())>().pretty_name() << endl;
//mydeclval()的返回类型 = class nmsp1::A
//mydeclval().myfunc的返回类型 = double

 

在原来类A的基础上增加私有的析构函数

namespace nmsp1 {class A {public://构造函数A(int i) {printf("A::A()函数执行了,this=%p\n", this);}double myfunc() {printf("A::myfunc()函数执行了,this=%p", this);return 12.1;}private:~A(){}};
}cout<<"mydeclval()的返回类型 = "<<type_id_with_cvr<decltype(nmsp2::mydeclval<nmsp1::A>())>().pretty_name() << endl;cout << "mydeclval().myfunc的返回类型 = " << type_id_with_cvr<decltype(nmsp2::mydeclval<nmsp1::A>().myfunc())>().pretty_name() << endl;//error:无法访问私有的析构函数
cout << "sizeof(mydeclval<A>()) = " << sizeof(nmsp2::mydeclval<nmsp1::A>()) << endl;//error
//因为返回类型本身导致为了遵循语义限制,编译器内部创建了临时的A类对象
//为了绕开予以限制,再设计mydeclval函数模板是,就不要返回T,可以返回T&,也可以返回T&&,
//这样从遵循予以限制方面来说,就不会创建临时的A类对象,这就是返回左值引用右值引用的好处//上处修改成引用就没有报错
namespace nmsp2 {template<typename T>T& mydeclval()noexcept;  //这里返回T
}

返回左值引用还是右值引用

class A {
public://构造函数A(int i) {printf("A::A()函数执行了,this=%p\n", this);}double myfunc() {printf("A::myfunc()函数执行了,this=%p", this);return 12.1;}private:~A(){}
};template<typename T>
T& mydeclval()noexcept;  using boost::typeindex::type_id_with_cvr;
cout << "decltype(mydeclval<A>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A>())>().pretty_name() << endl;cout << "decltype(mydeclval<A&>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A&>())>().pretty_name() << endl;cout << "decltype(mydeclval<A&&>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A&&>())>().pretty_name() << endl;
//decltype(mydeclval<A>())的返回类型 = class A&
//decltype(mydeclval<A&>())的返回类型 = class A&
//decltype(mydeclval<A&&>())的返回类型 = class A&

 

 

template<typename T>
T&& mydeclval()noexcept; using boost::typeindex::type_id_with_cvr;
cout << "decltype(mydeclval<A>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A>())>().pretty_name() << endl;cout << "decltype(mydeclval<A&>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A&>())>().pretty_name() << endl;cout << "decltype(mydeclval<A&&>())的返回类型 = " << type_id_with_cvr<decltype(mydeclval<A&&>())>().pretty_name() << endl;//decltype(mydeclval<A>())的返回类型 = class A &&
//decltype(mydeclval<A&>())的返回类型 = class A &
//decltype(mydeclval<A&&>())的返回类型 = class A &&

看上面的结果不难想象为啥标注库使用的是返回右值,返回右值拿到的类型更全面

调用引用限定符修饰的成员函数范例

class ALR {
public:void onArryValue() {cout << "ALR::onArryValue()函数执行了" << endl;}void oLvalue()& //只能被类ALR的左值对象调用
    {cout << "ALR::oLvalue()函数执行l" << endl;}void oRvalue()&& //只能被类ALR的右值对象调用
    {cout << "ALR::oRvalue()函数执行l" << endl;}
};template<typename T>
//T& mydeclval()noexcept;  
T&& mydeclval()noexcept;ALR alr;    //左值对象alr
alr.oLvalue();
//alr.oRvalue();//无法将左值绑定到右值引用
ALR().oRvalue();//这是临时对象,也是右值对象
decltype(mydeclval<ALR>().onArryValue());
decltype(mydeclval<ALR&>().oLvalue());
decltype(mydeclval<ALR&&>().oRvalue());//如果
template<typename T>
T& mydeclval()noexcept; decltype(mydeclval<ALR&&>().oRvalue());//Error

 

推导函数返回值范例

namespace nmsp2 {int myfunc(int a, int b)//函数类型一般由函数的返回值和参数决定
    {return a + b;}template<typename T_F,typename... U_Args>decltype(std::declval<T_F>()(std::declval<U_Args>()...)) TestFnRtnImpl(T_F func, U_Args... args){//decltype(std::declval<T_F>()(std::declval<U_Args>()...))的作用:根据函数类型以及函数参数类型推断函数返回值类型auto rtnvalue = func(args...);return rtnvalue;}
}auto result = nmsp2::TestFnRtnImpl(nmsp2::myfunc, 5, 8);//T_F = int (*)(int,int)
cout << result << endl;int (*fp_var)(int x, int y);//函数指针类型fp_var = int(*)(int,int)
int(*&&refer_fp_var)(int x, int y) = std::move(fp_var);//函数指针的右值引用,int (*&&)(int,int)

fp_var = nmsp2::myfunc;
cout << fp_var(1, 2) << endl;
cout << refer_fp_var(1, 2) << endl;

T_F = int (*)(int,int)类型,也就是函数指针类型

decltype(std::declval<T_F>()(std::declval<U_Args>()…)) = int ,也就是myfunc的返回类型

decltype(std::declval<T_F>()) = 是int (*&&)(int,int)函数指针的右值引用类型,decltype(std::declval<U_Args>()…)这种写法:推导出来的是两个int&&

namespace nmsp3 {//返回类型后置语法template<typename T_F, typename... U_Args>auto TestFnRtnImpl(T_F func, U_Args... args)->decltype(func(args...)){   //->decltype(func)  int(*)(int,int)auto rtnvalue = func(args...);return rtnvalue;}
}

 

https://blog.csdn.net/m0_51271123/article/details/121780256

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/30954.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Entity Framework Core中的并发处理

1.常见的并发处理策略 要了解如何处理并发,就要知道并发的一般处理策略 悲观并发策略 悲观并发策略,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守悲观的态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观并发策略…

openGauss 检查应用连接数

检查应用连接数 如果应用程序与数据库的连接数超过最大值,则新的连接无法建立。建议每天检查连接数,及时释放空闲的连接或者增加最大连接数。 操作步骤以操作系统用户omm登录数据库主节点。使用如下命令连接数据库。 gsql -d postgres -p 8000postgres为需要连接的数据库名称…

怎样才能不当数据泄露的下一个受害者?

在数字化时代,数据泄露成为了所有企业必须面对的难题。无论规模大小,每家公司都可能成为黑客攻击的目标,从而遭受数据泄露的风险。然而,通过采取一系列预防措施,企业可以极大地降低成为下一个受害者的可能性。 教育员工:增强数据安全意识 员工往往是数据泄露的最大风险源…

文件删除后空间未释放

文件删除后空间未释放第一步:找到处于delete状态的较大的文件,以及使用进程lsof |grep -i delete |sort -nrk7 |head |awk BEGIN{print "file-size","PID","system"}{print $7/1024/1024"M",$2,$9} | column -t 删除这个进程,然…

PyAlgoTrade-0-20-中文文档-四-

PyAlgoTrade 0.20 中文文档(四) SMA 交叉原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/sample_sma_crossover.html将此代码保存为 sma_crossover.py: from pyalgotrade import strategy from pyalgotrade.technical import ma from pyalgotrade.technical import cr…

PyAlgoTrade-0-20-中文文档-三-

PyAlgoTrade 0.20 中文文档(三) 工具原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/tools.htmlQuandl pyalgotrade.tools.quandl.``build_feed(sourceCode,tableCodes,fromYear,toYear,storage,frequency=86400,timezone=None,skipErrors=False,authToken=No…

PyAlgoTrade-0-20-中文文档-二-

PyAlgoTrade 0.20 中文文档(二) 经纪人 - 订单管理类原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/broker.html基础模块和类 类 pyalgotrade.broker.``Order(type_,action,instrument,quantity,instrumentTraits) 基类:object 订单的基类。参数:type(Order.…

VMware vSphere Bitfusion 4.5.4 - 面向 AI 和 ML 应用提供弹性基础架构

VMware vSphere Bitfusion 4.5.4 - 面向 AI 和 ML 应用提供弹性基础架构VMware vSphere Bitfusion 4.5.4 - 面向 AI 和 ML 应用提供弹性基础架构 请访问原文链接:VMware vSphere Bitfusion 4.5.4 - 面向 AI 和 ML 应用提供弹性基础架构,查看最新版。原创作品,转载请保留出处…