现代C++教程之新特性auto&decltype 02

本文详细介绍了C++中的auto和decltype关键字,阐述了它们如何自动推导变量类型,以及在C++14和17版本中的新功能,包括自动函数参数类型推导和结构化绑定。同时讨论了const与auto的结合使用和不同类型推导的规则。
摘要由CSDN通过智能技术生成

        auto和decltype是C++关键字,auto用于自动推导变量类型,decltype用于获取表达式的类型,它们简化了代码书写,提高了代码的可读性和灵活性。

auto类型推导

        当使用auto关键字时,编译器会根据变量的初始化表达式来自动推导出变量的类型。auto的基本语法如下:

auto variable_name = initial_value;

        其中,variable_name是我们想要定义的变量的名称,initial_value是该变量的初始值。auto关键字会根据initial_value的表达式来推导变量的类型。

在进行类型推导时,编译器会考虑以下规则:

  • 对于非引用类型的变量,auto会推导出与initial_value表达式类型相同的变量类型。
  • 对于引用类型的变量,auto会保留initial_value的引用类型。

例如:

auto number = 42; // 推导为int
auto& ref = number; // 推导为int&
auto* ptr = &number; // 推导为int*

此外,我们还需要注意以下几点:

  • auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代;
  • 使用 auto 类型推导的变量必须马上初始化;
  • auto 不能在函数的参数中使用(C++11和14,17可以)
  • auto 不能作用于类的非静态成员变量(也就是没有 static 关键字修饰的成员变量)中
  • auto 关键字不能定义数组
  • auto 不能作用于模板参数

1.1 auto在C++14和C++17中的差别       

         C++11和14中,auto不能在函数的参数中使用。但是C++14引入了泛型lambda表达式,使得函数对象可以自动推导参数类型。使用泛型lambda表达式时,我们可以使用auto来推导lambda函数的参数类型。例如:
 

auto printValue = [](auto value) {
    std::cout << value << std::endl;
};

printValue(42); // int类型
printValue(3.14); // double类型
printValue("Hello"); // const char* 类型

        在这个例子中,我们使用auto作为泛型lambda函数的参数类型,通过传递不同的参数类型,编译器会根据需要推导出参数类型,并正确地输出结果。

        在C++17中,引入了auto类型推导的增强功能,使得在函数参数中可以使用auto进行类型推导。这种新功能被称为自动函数参数类型推导(automatic function parameter type deduction)。使用自动函数参数类型推导,我们可以在函数参数中直接使用auto关键字,而无需显式指定参数类型。例如:

void printValue(auto value) {
    std::cout << value << std::endl;
}

        在这个例子中,函数printValue使用auto作为参数类型,编译器会根据实际传入的参数类型来自动推导出参数类型。这样可以使函数更加通用,可以传递不同类型的参数而无需进行重载或者模板函数的定义。注意,自动函数参数类型推导只能用于非模板函数中,模板函数依然需要指定参数类型。

        此外,在C++17中还引入了通过结构化绑定(structured bindings)来进行自动解包。结构化绑定允许我们在使用auto声明变量的同时,将其绑定到复杂数据结构(如pair、tuple、数组等)中的成员变量上。

std::pair<int, std::string> person = { 25, "John" };
auto [age, name] = person;
std::cout << "Age: " << age << ", Name: " << name << std::endl;

        这个例子中,我们使用auto结合结构化绑定的方式,将person中的成员变量分别赋给age和name两个变量,无需显式指定类型。

总结起来,在C++17中,引入了自动函数参数类型推导和结构化绑定的功能,使得我们可以更方便地使用auto进行类型推导,提高代码的可读性和简洁性。

1. 2  auto和const

        当使用auto关键字进行类型推导时,const修饰符的使用会影响推导结果以及变量的可修改性。以下是一些和const一起使用auto时的注意点:

  • const auto

        如果初始化表达式是const的,使用const auto进行类型推导将推导出const限定的类型。在这种情况下,推导出的类型是不可修改的,即使尝试修改x的值也会导致编译错误。

 const auto x = 10; // 推导为const int
  • auto const

        auto和const关键字的顺序是可以颠倒的,使用auto const进行类型推导也会得到const限定的类型。同样地,在这种情况下,推导出的类型是不可修改的。

auto const y = 20; // 推导为const int
  • auto& const

        在使用auto进行引用类型的推导时,const修饰符的位置也影响推导结果。auto& const将推导出const引用类型。

int z = 30;
auto& const ref = z; // 推导为const int&

这里,ref是一个指向int类型的常量引用,所以不能通过ref来修改z的值。需要注意的是,auto和const的组合使用可以提供更好的代码清晰度和类型安全性。通过使用const限定的自动类型推导,可以防止在使用变量时不小心修改其值,从而提高程序的可靠性和稳定性。

        总结起来,使用auto和const可以为变量的类型推导添加限制和保护,确保推导的结果是符合预期的 const 类型。这样可以提高代码的可读性和更好地表达意图。

1.3 auto和初始化方式

使用auto进行类型推导时,变量的初始化方式会影响推导出的类型。

  • 如果通过拷贝初始化(使用=)初始化auto变量,推导出的类型会去除顶层const和引用特性。
int x = 10;
auto value = x; // 推导为int
  • 如果通过直接初始化(使用花括号{})初始化auto变量,推导出类型会保留顶层const和引用特性
int x = 10;
auto& ref = { x }; // 推导为const int&

decltype类型推导

        auto 和 decltype 关键字都可以自动推导出变量的类型,但它们的用法是有区别的:

auto varname = value;

decltype(exp) varname = value

        其中,varname 表示变量名,value 表示赋给变量的值,exp 表示一个表达式。uto 根据=右边的初始值 value 推导出变量的类型,而 decltype 根据 exp 表达式推导出变量的类型。另外,auto 要求变量必须初始化,而 decltype 不要求。原则上讲,exp 就是一个普通的表达式,它可以是任意复杂的形式,但是我们必须要保证 exp 的结果是有类型的,不能是 void。

2.1 decltype推导规则

        在推导规则方面,decltype遵循以下几个基本原则:

  • 对于一个对象或变量,decltype的推导结果将是该对象或变量的类型
int x = 10;
decltype(x) y; // 推导结果为int
  • 对于一个表达式,decltype的推导结果将是该表达式的类型
 int x = 10;
 decltype(x * 2) y; // 推导结果为y为int
  • 对于一个函数调用表达式,decltype的推导结果将是函数返回类型
int add(int a, int b) {
    return a + b;
}

decltype(add(2, 3)) result; // 推导结果result类型为int
  • 对于一个左值表达式,decltype会保留其引用类型
 int x = 10;
 int& ref = x;
 decltype(ref) y = x; // 推导结果为int&
  • 对于一个右值表达式,decltype会跟踪其值类型,并将其推导为非引用类型
int x = 10;
decltype(x + 2) y; // 推导结果为int
  • 当使用decltype推导某个名称时,如果该名称是一个未被定义的变量(即非法名称),编译器会报错。

        这些规则使得decltype成为了一个有用的工具,在类型推导、模板元编程等场景中发挥重要作用。通过使用decltype,我们可以编写更加通用的代码,减少类型重复和手动维护的工作,提高代码的可读性和可维护性。

2.2 高级用法和特性

  • decltype(auto)

        decltype(auto)用于推导任意表达式的类型,包括顶层const和引用。它可以用于定义变量,函数返回类型以及lambda表达式。

 int x = 10;
 int& ref = x;
 decltype(auto) y = ref; // 推导结果为int&
  • decltype和模板

        在函数模板中,可以使用decltype推导函数模板参数的类型。

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
     return t + u;
}

        上述示例中,decltype(t + u)用于推导参数t和u相加后的类型,进而作为函数的返回类型。

  • decltype和decltype(auto)的引用折叠

         当使用decltype(auto)推导引用类型时,会进行引用折叠,让推导结果更符合预期。

int x = 10;
int& ref = x;
decltype(auto) y = ref; // 推导结果为int&

         在上述示例中,y被推导为int&,而不是int。

  • decltype的嵌套使用

decltype可以进行嵌套使用,用于推导复杂表达式的类型。

int x = 10;
decltype(decltype(x)) y = x; // 推导结果为int

        在上述示例中,第一个decltype(x)推导结果为int,然后再次使用decltype推导int的类型,结果仍为int。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泽箬酱咧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值