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';
}

四、总结

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

相关内容

热门资讯

永远会用安卓系统的手机 亲爱的手机控们,你是否也有那么一款手机,它陪伴你度过了无数个日夜,成为了你生活中不可或缺的一部分?没...
安卓系统怎么添加公众号,安卓系... 你是不是也和我一样,对安卓手机上的公众号情有独钟呢?想要把那些有趣的公众号添加到手机里,随时随地都能...
仿苹果系统怎么改回安卓系统,轻... 你是不是也和我一样,曾经被苹果系统的魅力所吸引,然后不小心把手机换成了安卓呢?现在,突然发现安卓的某...
oppor11plus安卓系统... 你有没有注意到,最近手机圈里又掀起了一股热潮?没错,就是OPPO R11 Plus这款手机。这款手机...
安卓系统重新洗牌教程,从重新洗... 你有没有发现,安卓系统最近好像经历了一场大洗牌?别急,别急,让我来给你详细介绍一下这个安卓系统重新洗...
安卓12系统改画质,尽享极致流... 你有没有发现,最近你的安卓手机好像变得不一样了?没错,就是那个神秘的安卓12系统,它悄悄地给你带来了...
小米11系统是安卓几,探索新一... 你有没有发现,最近小米11这款手机在市场上可是火得一塌糊涂呢!那么,问题来了,小米11的系统是安卓几...
安卓版系统下载安装 你有没有想过,为什么你的手机总是那么卡,那么慢?别急,今天就来给你揭秘,如何让你的安卓手机焕然一新,...
安卓换苹果系统更新多久,体验无... 你有没有想过,当你把心爱的安卓手机换成苹果,那系统更新到底要等多久呢?这可是不少人在换机时都会关心的...
如何升级华为的安卓系统,轻松提... 亲爱的手机控们,你是不是也和我一样,对华为的安卓系统充满了好奇和期待?想要让你的华为手机焕然一新,体...
好用系统插件推荐安卓手机,提升... 你有没有发现,手机用久了,是不是觉得有点力不从心?别急,今天就来给你安利一波好用系统插件,让你的安卓...
x3鸿蒙系统和安卓系统,探索x... 你知道吗?最近手机圈里可是热闹非凡呢!各大品牌纷纷推出新机,而其中最引人注目的莫过于华为的新操作系统...
安卓系统优化手机软件,打造流畅... 你有没有发现,你的安卓手机最近变得有点“慢吞吞”的?别急,别急,今天就来给你支几招,让你的安卓手机焕...
安卓车机系统显示歌词,打造沉浸... 亲爱的车友们,你是否在驾驶过程中,被那美妙的旋律和歌词所吸引,却又因为无法专注于路面而感到困扰?别担...
安卓系统硬件是否损坏 手机突然卡顿,屏幕闪烁不定,是不是安卓系统的硬件出了问题?别急,今天就来给你详细剖析一下安卓系统硬件...
3310安卓4g系统,智能升级 你有没有听说过3310安卓4G系统?这可是最近科技圈里的小热门呢!想象一个经典的诺基亚3310,竟然...
小米用的安卓系统吗,引领智能生... 你有没有想过,那个你每天不离手的手机,它的操作系统到底是谁家的“孩子”?今天,咱们就来聊聊这个话题—...
安卓系统厉害的游戏,盘点那些令... 你有没有发现,安卓系统上的游戏真的是越来越厉害了?没错,我就要给你好好盘点一下那些让人欲罢不能的安卓...
安卓手机系统提有声音,唤醒你的... 你有没有发现,最近你的安卓手机系统突然变得特别贴心呢?没错,就是那个一直默默陪伴你的小家伙,现在竟然...
安卓9系统设置密码破解,轻松应... 你有没有遇到过这种情况:手机里装了安卓9系统,不小心设置了密码,结果现在想找回数据,却因为密码而头疼...