c++11中的declval和decltype
创始人
2024-04-19 05:20:45
0

一、declval的介绍

std::declval定义在头文件中:

template
typename std::add_rvalue_reference::type declval() noexcept;

看定义它应该是返回一个右值引用(在T 是(可有 cv 限定的) void ,此情况下返回类型是 T)。在c++的文档中介绍说其可以不通过构造函数就可以使用T的成员函数,它只能用于不求值语境。这个模板函数没有具体的实现,无法调用。一般用于与decltype,sizeof等关键字配合来进行类型推导、占用内存空间(某一类型的对象的引用的占位符)计算等,一般在模板编程中应用较多。
需要注意的是,std::declval是在编译期进行处理完成的,也就是说,它在编译期过程中生成一个值对象,但是其并不会被编译为可执行期的二进制实体。或者可以这样理解,在开发过程中,有时候儿并不需要真正的拿到这个实例对象,而只是来对这个对象进行一个类型描述,如果真想用其来完成某种计算,一般外面会罩上decltype ,这也是在网上往往这两个模板函数放在一起分析的原因。这种情况是不是有些熟悉?在模板元编程里是不经常遇到这种情况,所以其在模板的元编程里应用也比较多。
下面看一个占位符的示例:

// 在下面的情况中,这里使用了std::declval,在调用运算符?:的时候就不需要调用 T1 和 T2 的(默认)构造函数
#include 
template() : std::declval())> >
R GetMax (T1 a, T2 b)
{return b < a ? a : b;
}

弄明白了这个,就明白了std::declval的用处了。

二、decltype介绍

std::decltype可以在编译期内推导表达式所得值的类型,在上面的declval中可以看到一起使用的效果。其实看代码也可以明白,就是推导出类型结果。拿到这个类型结果,就可以搞事情了。可是这里面有一个问题,为什么它是一个关键字?这个类型推导多么简单的一个事儿。其实不然,如果后面有一大堆的表达式,复杂的不得了,你就会发现,用这个关键字可就真的好。那什么情况下会有一大串的表达式呢?仍然是元编程中多。谁也不想把一大串的模板声明不断的抄来抄去,这老麻烦了。也就是说,std::decltype,auto,using在某些情况下起到的作用有些类似。在前面也可以看到这些用法的使用,这里就不再做赘述。它的语法定义如下:

decltype ( 实体 )	(1)	(C++11 起)
decltype ( 表达式 )	(2)	(C++11 起)

std::decltype为什么配合std::declval一起使用,有一个重要原因就是前者需要推导类型时对象要求需要有默认构造函数,而后者不需要。这就在模板元编程中起到了重要的作用。另外,纯虚类也是一个问题,declval 可以绕开纯虚基类不能实例化的问题。std::decltype和逗号表达式一起工作时,需要考虑逗号表达式是从左到右依次计算,最后一个做为返回值,这个在以前的变参模板中也用到过。看一下例子:

template
auto len (T const&& t) -> decltype((void)(t.size()) , T::size_type)
{return t.size();
}

这个size函数可以说做一个Assert,如果T中有这个函数,则替换成功,否则直接报错。这也算是一个小技巧。

三、例程

这两个功能可以在一起使用,然后创造一些小惊喜。
看一看std::declval的例程:

#include 
#include struct Default { int foo() const { return 1; } };struct NonDefault
{NonDefault() = delete;int foo() const { return 1; }
};int main()
{decltype(Default().foo()) n1 = 1;                   // n1 的类型是 int
//  decltype(NonDefault().foo()) n2 = n1;               // 错误:无默认构造函数decltype(std::declval().foo()) n2 = n1; // n2 的类型是 intstd::cout << "n1 = " << n1 << '\n'<< "n2 = " << n2 << '\n';
}

是不是非常简单明了,其实学习这些东西,就得从最基础最简单的地方,把基本的知识掌握了,才能使用上面的各种变化和技巧。

再看一下std::decltype的例程:

#include 
#include struct A { double x; };
const A* a;decltype(a->x) y;       // y 的类型是 double(其声明类型)
decltype((a->x)) z = y; // z 的类型是 const double&(左值表达式)template
auto add(T t, U u) -> decltype(t + u) // 返回类型依赖于模板形参
{                                     // C++14 开始可以推导返回类型return t+u;
}int main() 
{int i = 33;decltype(i) j = i * 2;std::cout << "i = " << i << ", "<< "j = " << j << '\n';std::cout << "i 和 j 的类型相同吗?"<< (std::is_same_v ? "相同" : "不同") << '\n';auto f = [](int a, int b) -> int{return a * b;};decltype(f) g = f; // lambda 的类型是独有且无名的i = f(2, 2);j = g(3, 3);std::cout << "i = " << i << ", "<< "j = " << j << '\n';
}

在c++17以后,还可以std::delctype(auto)这种形式来推导相关的类型,例程可以看一下前面的拖尾类型的文章,上面有c++14和c++17两种的不同方式,就用到这种形式。
看了上面的两个应用,再看一个网上的纯虚类的应用:

#include namespace {struct base_t { virtual ~base_t(){} };templatestruct Base : public base_t {virtual T t() = 0;};templatestruct A : public Base {~A(){}virtual T t() override { std::cout << "A" << '\n'; return T{}; }};
}int main() {decltype(std::declval>().t()) a{}; // = int a;decltype(std::declval>().t()) b{}; // = int b;std::cout << a << ',' << b << '\n';
}

四、总结

其实很多东西,基础的太简单,仿佛看一眼就会了。但是过了好久,又突然发现,这种简单的东西自己从来没用过。也不问为什么,反正是觉得用不到。忽然有一天,看到人家大牛的代码里这种简单的知识组合起来满飞,大脑于是一片迷茫,根本不知道怎么回事儿。回过头来看吧,又觉得基础的东西太多,不看吧,确实又不明白代码。问人吧,又没人可问。于是,大多数人可能就不了了之了。
学习在这里突然断了片儿,上,够不着;下,不甘心。怎么破除这种情况呢?还是得反过来,把基础重新牢牢打好,把大牛的复杂代码分解成一块一块的不断分析,从细节入手,除了一些特别孤僻的技巧,一般来说,都会慢慢搞定。从生到熟,从熟到初步应用,到自主应用,甚至自由组合放飞技术。这都是大有可能的。努力吧!

相关内容

热门资讯

安卓系统相机不能启动,安卓相机... 手机里的安卓系统相机突然不能启动了,这可真是让人头疼啊!你有没有遇到过这种情况呢?别急,今天就来跟你...
安卓原生系统时间校准,基于安卓... 手机时间不准了?别急,我来教你如何轻松搞定安卓原生系统时间校准! 话题引入:手机时间不准,是不是让你...
主机系统内存和安卓联机,主机系... 你有没有想过,为什么你的手机在玩大型游戏时总是卡得要命?又或者,为什么你的电脑在处理复杂任务时,反应...
安卓如何手机上刷系统,轻松升级... 你有没有想过,你的安卓手机是不是已经有点儿“老态龙钟”了呢?别急,别急,今天就来教你怎么给它来个“青...
苹果系统观战安卓好友,观战新体... 亲爱的读者,你是否也有过这样的经历:一边享受着苹果系统的优雅与流畅,一边又忍不住好奇地观战安卓好友们...
安卓系统最好是哪个,最佳生成方... 你有没有想过,手机里的安卓系统哪个才是最适合你的呢?在这个信息爆炸的时代,手机已经成为了我们生活中不...
改时间安卓系统vivo,探索v... 你有没有发现,最近你的vivo手机有点儿“慢吞吞”的?别急,别急,让我来给你支个招儿,让你的安卓系统...
安卓系统的旋钮在哪,旋钮生成位... 你有没有发现,有时候手机上的小细节也能让人头疼不已?比如说,安卓系统的旋钮在哪?这问题看似简单,但不...
安卓手机app系统软件,探索安... 你有没有发现,现在手机里的app简直就像是个小宇宙,各种功能应有尽有,让人眼花缭乱。尤其是安卓手机,...
win111安卓子系统,开启跨... 哇,你有没有听说最近的大新闻?那就是Windows 11的安卓子系统!是的,你没听错,Windows...
游戏摇杆连安卓系统电视,畅享游... 你有没有想过,家里的安卓系统电视也能玩起游戏来?没错,就是那种让你手舞足蹈、热血沸腾的游戏摇杆!今天...
nokia平板系统兼容安卓,尽... 你有没有想过,那些曾经陪伴我们度过无数时光的诺基亚手机,现在竟然也能摇身一变,成为平板电脑的得力助手...
安卓原生系统是什么品牌,探索安... 你有没有想过,为什么你的手机那么流畅,界面那么美观?这背后,可是有一个强大的“大脑”在默默支撑着呢!...
安卓3大操作系统,从三大分支看... 你知道吗?在安卓的世界里,操作系统可是有着三大巨头呢!它们就像安卓世界的三驾马车,各自有着独特的魅力...
开源文件管理系统安卓,打造个性... 你有没有想过,手机里那些乱糟糟的文件,要是能有个好帮手,生活该有多轻松啊?今天,就让我带你走进一个神...
手机删除了系统安卓市场,手机系... 手机里的安卓市场突然不见了,这可怎么办呢?别急,让我来给你详细说说这个棘手的问题,让你轻松应对!一、...
安卓系统写脚本软件下载,基于安... 你有没有想过,你的安卓手机或者平板电脑,除了用来刷剧、玩游戏,还能变成一个强大的工作助手呢?没错,就...
安卓系统有哪些机型好,探索顶级... 你有没有想过,安卓系统里的手机型号那么多,哪一款才是最适合你的呢?别急,今天我就来给你好好盘点看看安...
安卓系统之间如何互传,安卓设备... 你是不是也和我一样,手机里存了那么多好东西,却苦于不能和好友分享呢?别急,今天就来教你怎么用安卓系统...
安卓系统启动修改工具,安卓系统... 你有没有想过,你的安卓手机启动速度竟然可以像火箭一样快?没错,这就是今天我要跟你分享的神秘工具——安...