(C++ Std 学习) decltype 定义与使用

27 篇文章 0 订阅
24 篇文章 1 订阅
本文详细介绍了C++11的decltype特性,包括其定义、使用场景和规则。通过实例代码分析,展示了decltype如何根据表达式类型推断变量类型,以及在模板函数返回类型推导中的应用。同时,文中还讨论了在实际工程代码中使用decltype的情况,以提高代码的灵活性和效率。
摘要由CSDN通过智能技术生成

(C++ Std 学习) decltype 定义与使用

概述和背景

     在自己编写代码的项目中,有些地方碰到同事特别喜欢使用auto和decltype作为使用的方法,就是比较喜欢用C++11这个特性,我才发现自己之前对这方面有些抵触,我个人习惯是能不用auto就不用auto,不然一堆auto别人看了也不好理解到底是个什么类型,会导致代码可读性变的很差,不过还是意识到,虽然我个人不喜欢用,但是大趋势是同事之间会越来越多的人来使用这种C++11的新特性,所以还是要认真地看看学习一下这东西,因此就有了这篇文章的诞生。

参考文本和自行翻译

     声明: 下面这节是从英文文档中我自己想办法翻译过来学习用的!
     下面这一整节主要来自于从C++ Reference里面的学习和翻译的过程:

定义

在这里插入图片描述
解释:
关于xvalue,左值,prvalue的一些解释,可以参考大佬的文章:C++ lvalue,prvalue,xvalue,glvalue和rvalue详解(from cppreference)

  • 如果参数是未括号化的id表达式或未括号化的类成员访问表达式,则decltype会产生此表达式命名的实体的类型。如果没有这样的实体,或者参数指定了一组重载函数,则程序格式错误。
  • 如果参数是命名结构化绑定的非括号id表达式,则decltype会产生引用的类型(在结构化绑定声明的规范中进行了描述)。(C++17之后)
  • 如果参数是命名为非类型模板参数的非括号id表达式,则decltype会产生模板参数的类型(如果使用占位符类型声明模板参数,则在执行任何必要的类型推导之后)。(C++ 20 之后)
  • 如果参数是类型T的任何其他表达式,则:
    • 如果表达式的值类别是xvalue,则decltype产生T &&;
    • 如果表达式的值类别为左值,则decltype产生T&;
    • 如果表达式的值类别为prvalue,则decltype产生T
  • 如果expression是返回类类型的prvalue的函数调用,或者是右运算数就是该函数调用的逗号表达式,则不会为该prvalue引入临时对象。
  • 如果expression是除(可能带有括号的)立即调用之外的一个prvalue(自C ++ 20起),则不会从该prvalue实现一个临时对象:此类prvalue没有结果对象。
  • 该类型不必是完整的或具有可用的析构函数,并且可以是抽象的。 该规则不适用于子表达式:在decltype(f(g())中,g()必须具有完整类型,而f()则不需要。
  • 请注意,如果对象的名称带有括号,则将其视为普通的左值表达式,因此decltype(x)decltype((x))通常是不同的类型。
  • 当声明使用标准符号难以或不可能声明的类型(例如与lambda相关的类型或依赖于模板参数的类型)时,decltype很有用。

案例代码分析

#include <iostream>
#include <type_traits>
 
struct A { double x; };
const A* a;

// y的类型为double(声明的类型)
decltype(a->x) y;       // type of y is double (declared type)
// z的类型为const double&(左值表达式)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)
 
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters(返回类型取决于模板参数)
                                      // return type can be deduced since C++14(从C ++ 14开始就可以推论返回类型)
{
    return t + u;
}
 
int main()
{
    int i = 33;
    decltype(i) j = i * 2;
 
    std::cout << "i and j are the same type? " << std::boolalpha
              << std::is_same_v<decltype(i), decltype(j)> << '\n';
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
 
    auto f = [](int a, int b) -> int
    {
        return a * b;
    };
    
 	// lambda函数的类型是唯一的且未命名
    decltype(f) g = f; // the type of a lambda function is unique and unnamed
    i = f(2, 2);
    j = g(3, 3);
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
}

     运行结果:

i and j are the same type? true
i = 33, j = 66
i = 4, j = 9

自己编写的代码中使用分析

     想到写这篇文章的原因也是因为自己工程代码中,会时不时遇到这样的写法:


// Deal with indices
auto nIdxCountToAdd = nCount;
auto && indices = newPNode->getINdices();

indeces.resize(nIdxCountToAdd  * 2 - 2);

for (decltype(nIdxCountToAdd ) i = 0; i < nIdxCountToAdd - 1; ++i) 
{
	indices[i * 2] = (TZINT32)(i);
	indices[i * 2 + 1] = (TZINT32)(i + 1);
}

就是用 nIdxCountToAdd 确定循环变量i的类型的一个过程。

个人格言

用心去感受你自己需要坚持的生活,未来慢慢会给你答案的。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值