《深入理解C++11》笔记-decltype

上一篇:《深入理解C++11》笔记-auto类型
本篇将介绍decltype的用法。decltype与auto类似,也能进行类型推导,但是用法有一定的区别,decltype推导出的类型能作为类型声明变量:

int main()
{
    int i = 1;
    decltype(i) j = 2;
    std::cout << typeid(j).name() << std::endl;   // int

    getchar();
    return 0;
}

decltype的应用

一种是decltype和typedef/using的合用:

using size_t = decltype(sizeof(0));
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);

另外,与auto相同可以用于简化代码增强可读性:

    std::map<std::string, std::string> mapString;

    using mapitor = decltype(mapString.begin());
    for (mapitor i = mapString.begin(); i != mapString.end(); ++i)
    {

    }

    for (decltype(mapString)::iterator i = mapString.begin(); i != mapString.end(); ++i)
    {

    }

还有一种用法是重用匿名类型,但是实际开发中匿名类型一般是为了不让外部进行重用,所以使用这种用法前需要多考虑:

struct {
    int i = 1;
}anon;


int main()
{
    decltype(anon) anon_struct;
    anon_struct.i;

    return 0;
}

还能扩大模板泛型的能力:

template<typename T1, typename T2>
void sum(const T1& a, const T2& b, decltype(a + b)& s)   // 自动推导输出参数s的类型
{
    s = a + b;
}

int main()
{
    int a = 1;
    long b = 2;
    long s = 0;
    sum(a, b, s);   // 使用该模板需要提前推导出输出参数的类型,例如此处输出为long

    return 0;
}

decltype推导四规则

int i = 0;
decltype(i) a;
decltpye((i)) b;    // 编译失败,提示引用类型

如上代码,decltype双括号无法通过编译,因为decltype推导类型会有几个规则 - decltype(type):

  • 如果type是一个没有带括号的标记符表达式(可以理解为变量名称)或类成员访问表达式,那么decltype(type)就是type对应的类型。此外,如果type是一个重载的函数,则会导致编译失败。
  • 否则,假设type的类型为T,且是一个将亡值,那么decltype(type)为T&&。
  • 否则,如果type是一个左值,那么decltype(type)为T&。
  • 否则,decltype(type)为T。

再回头看之前的代码decltype(i) a;使用了规则1,因为i是没有带括号的标记符表达式,所以推导的类型为int。而decltpye((i)) b;是带括号的标记符表达式,所以使用了规则3,类型为int&。

我们再通过一些例子来详细了解一下以上规则的使用:

struct S { double d; } s;
int func(int);
int func(double);
int&& rvalue();
const bool isvalue(int);

int main()
{
    int i = 0;
    int arr[5] = { 0 };
    int* ptr = arr;

    decltype(arr) var1;   // int[5],不带括号的标记符表达式
    decltype(ptr) var2;   // int*,不带括号的标记符表达式
    decltype(s.d) var3;   // double,不带括号的成员访问表达式
    decltype(func) var4;  // 编译失败,是重载的函数

    decltype(rvalue()) var5 = 1; // int&&,将亡值

    // 左值推导为类型的引用
    decltype((i)) var6 = i;     // int&带括号的左值
    decltype(++i) var7= i;      // int&,++i返回i的左值
    decltype(arr[3]) var8 = i;  // int&,[]返回i的左值
    decltype(*ptr) var9 = i;    // int&,*返回i的左值
    decltype("lvalue") var10 = "lvalue";  // const char(&)[], 字符串字面常量为左值

    // 以上都不是,推导为本类型
    decltype(1) var11;    // int,处理字符串字面常量以外的值为右值
    decltype(i++) var14;  // int, i++返回右值
    decltype((isvalue(1))); // const bool,圆括号可以忽略

    return 0;
}

cv限制符的继承与冗余的符号

上一篇中说到auto不能带走cv限制符(const、volatile),decltype是能够带走的。不过,如果对象定义中有const或volatile限制符,使用decltype推导时,其成员不会继承cv限制符。

int main()
{
    int i = 0;
    int& j = i;
    decltype(i)& var1 = i;     // int& 类型
    decltype(j)& var2 = i;     // int& 类型,推导出的类型已经有引用,冗余的引用会被忽略

    int* ptr = &i;
    //decltype(ptr)* var3 = &i;    // 编译失败,int**裂隙不能指向int*类型
    decltype(ptr)* var4 = &ptr;    // int**类型,推导出的类型是指针,不会被忽略

    const int k = 0;
    decltype(k) var5 = 1;          // const int类型
    const decltype(k) var6 = 1;    // const int类型,推导出的类型已经有const,冗余的const会被忽略

    return 0;
}

可以看到,decltype推导的类型有时候会忽略一些冗余的符号,包括const、volatile、引用符号&。

下一篇:《深入理解C++11》笔记-追踪返回类型

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值