C++ 11 decltype 和decltype(auto)

decltype
decltype是C++11新增的关键字,主要用于提取变量和表达式的类型。
decltype的语法形式为:decltype(e),这里e是一个表达式,而decltype(e)是一个类型指示符。decltype的结果不是值,而是一个类型。


decltype的语法规则主要有以下四条:
(1) 如果e是一个没有用小括号括起来的标识符表达式或类成员存取表达式,那么decltype(e)的结果类型为该表达式中标识符的声明类型。
注:这里的小括号是指表达式e自身带的小括号,而不是decltype(e)中的小括号。
(2) 如果e是T类型的x值,那么decltype(e)的结果类型为T&&。
注:x值(xvalue)是C++11新引入的值的种类,介于传统的左值和右值之间。最常见的x值为无名右值引用。
(3) 如果e是T类型的左值,那么decltype(e)的结果类型为T&。
注:同时满足规则1和规则3的情况下,规则1优先。
(4) 如果e是T类型的纯右值,那么decltype(e)的结果类型为T。
注:纯右值(prvalue)即传统右值。字面量以及临时对象都是纯右值。
测试代码及出错信息

#include <iostream>
 
template<typename T>
T f();
 
struct S {int a;};
 
int main()
{
    int a = 0;
    S s;
    f<decltype(a)>();
    f<decltype(s.a)>();
    f<decltype(std::move(a))>();
    f<decltype((a))>();
    f<decltype((s.a))>();
    f<decltype(0)>();
 
    decltype(a) b = a; // int b = a;
    decltype((a)) c = a; // int& c = a;
}

main.cpp:(.text.startup+0x5): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0xa): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0xf): undefined reference to `int&& f<int&&>()'
main.cpp:(.text.startup+0x14): undefined reference to `int& f<int&>()'
main.cpp:(.text.startup+0x19): undefined reference to `int& f<int&>()'
main.cpp:(.text.startup+0x1e): undefined reference to `int f<int>()'


这段代码使用了一种特殊技巧来查看decltype的结果类型。代码中定义了一个未被实现的函数模板f,该函数模板有一个类型参数T。如果用某个类型T来调用该函数模板,编译器就会因找不到函数模板的定义而输出”T f<T>()未被定义“的出错信息。也就是说,利用该函数模板,我们便可以在编译器所输出的出错信息中检查模板参数T的实际类型。在main函数内,我们充分利用了这一个技巧,通过利用decltype的结果类型调用该函数模板来让编译器输出相应的类型。
从出错信息中可以得知:

decltype(a)和decltype(s.a)的结果类型为int。(适用规则1)
理由:a是未带外围小括号的标识符,s.a是未带外围小括号的类成员存取表达式。变量a的声明类型是int,S结构的成员变量a的声明类型也是int。
decltype(std::move(a))的结果类型为int&&。(适用规则2)
理由:std::move(a)是无名右值引用,是x值的一种。
decltype((a))和decltype((s.a))的结果类型为int&。(适用规则3)
理由:(a)和(s.a)都是带外围小括号的左值引用,是左值。
decltype(0)的结果类型为int。(适用规则4)
理由:0是纯右值(即传统右值)。
decltype(auto)
decltype(auto)是C++14新增的类型指示符,可以用来声明变量以及指示函数返回类型。
当decltype(auto)被用于声明变量时,该变量必须立即初始化。假设该变量的初始化表达式为e,那么该变量的类型将被推导为decltype(e)。也就是说在推导变量类型时,先用初始化表达式替换decltype(auto)当中的auto,然后再根据decltype的语法规则来确定变量的类型。
decltype(auto)也可以被用于指示函数的返回值类型。假设函数返回表达式e,那么该函数的返回值类型将被推导为decltype(e)。也就是说在推导函数返回值类型时,先用返回值表达式替换decltype(auto)当中的auto,然后再根据decltype的语法规则来确定函数返回值的类型。

#include <iostream> 
template<typename T>  
T f();
 
struct S {int a;};
 
int a = 0;
S s;
decltype(auto) g1() {return s.a;}
decltype(auto) g2() {return std::move(a);}
decltype(auto) g3() {return (a);}
decltype(auto) g4() {return (0);}
 
int main()
{
    decltype(auto) i1 = a;
    decltype(auto) i2 = std::move(a);
    decltype(auto) i3 = (s.a);
    decltype(auto) i4 = (0);
    f<decltype(i1)>();
    f<decltype(i2)>();
    f<decltype(i3)>();
    f<decltype(i4)>();
    f<decltype(g1())>();
    f<decltype(g2())>();
    f<decltype(g3())>();
    f<decltype(g4())>();
}

main.cpp:(.text.startup+0x5): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0xa): undefined reference to `int&& f<int&&>()'
main.cpp:(.text.startup+0xf): undefined reference to `int& f<int&>()'
main.cpp:(.text.startup+0x14): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0x19): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0x1e): undefined reference to `int&& f<int&&>()'
main.cpp:(.text.startup+0x23): undefined reference to `int& f<int&>()'
main.cpp:(.text.startup+0x28): undefined reference to `int f<int>()'


这段代码使用了同样的编程技巧来查看decltype(auto)的结果类型。
从出错信息中可以得知:

变量i1的类型等同于decltype(a)的结果类型,即int。(适用规则1)
函数g1的返回值类型等同于decltype(s.a)的结果类型,即int。(适用规则1)
变量i2的类型等同于decltype(std::move(a))的结果类型,即int&&。(适用规则2)
函数g2的返回值类型等同于decltype(std::move(a))的结果类型,即int&&。(适用规则2)
变量i3的类型等同于decltype((s.a))的结果类型,即int&。(适用规则3)
函数g3的返回值类型等同于decltype((a))的结果类型,即int&。(适用规则3)
变量i4的类型等同于decltype((0))的结果类型,即int。(适用规则4)
函数g4的返回值类型等同于decltype((0))的结果类型,即int。(适用规则4)
————————————————
版权声明:本文为CSDN博主「zwvista」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zwvista/article/details/54571821

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值