C++11 auto、decltype、is_reference、is_rvalue_reference/is_lvalue_reference、typeid

#include <iostream>
#include <type_traits> // 存在is_rvalue_reference、is_lvalue_reference、is_reference模板
using namespace std;
/*
左值:可以取地址的、有名字的就是左值;
右值:不可以取地址的、没有名字的是右值;右值是由两个概念构成的,一个是纯右值,另一个则是将亡值。
左值引用:对左值的引用,是具名变量值的别名,声明时必须初始化,不能对左值引用重定义。常量左值引用const T&,既可以绑定左值又可以绑定右值。
右值引用:对右值的引用,是不具名(匿名)变量的别名,声明时必须初始化,不能对右值引用重定义。已命名的右值引用,编译器会认为是个左值。
*/
// 移动语义
// std::move(lvalue) 的作用就是把一个左值转换为右值,当然传入一个右值,输出还是右值
// 值得注意的是: 使用move意味着,把一个左值转换为右值,原先的值不应该继续再使用(承诺即将废弃)
// 完美转发
// std::forward()完美转发实现了参数在传递过程中保持其值属性的功能,即若是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。
// 引用折叠
// 右值引用的右值引用,即X&& &&折叠为X&&
// 其他情况均折叠成左值引用,如X& &、X& &&、X&& &都折叠成X&
// 参数模板推断
// template<typename T>
// void f(T&&);
// 根据引用折叠原则,当将一个左值传递给一个参数是右值引用的函数,且此右值引用指向模板类型参数(T&&)时,编译器推断模板参数类型为实参的左值引用
// 当将一个右值引用传递给一个参数是右值引用的函数,且此右值引用指向模板类型参数(T&&)时,编译器推断模板参数类型为实参的右值引用
// auto
// 可以通过变量赋值,推导出变量的类型
// auto会忽略引用,如int i = 0 ,&r = i; auto a = r; //这里的a类型为int,并非int&
// auto会忽略顶层的const,如int i = 0; const int ci = i, &cr = ci; auto a = ci; // a 为一个int, 顶层const被忽略
// decltype
// 可以提取变量的类型,并通过这个类型区定义新的变量,并可以不去初始化变量,如 int a =0; decltype(a) b; // b是int型,而且可以不初始化
// decltype可以反会变量的顶层const和引用类型
int main()
{
// type_traits头文件中的模板可以判断引用类型
cout << is_reference<int>::value << endl; // 0
cout << is_rvalue_reference<string &&>::value << endl; // 1
cout << is_lvalue_reference<string &> ::value << endl; // 1
cout << is_rvalue_reference<const string &&>::value << endl; // 1
cout << is_lvalue_reference<const string &> ::value << endl; // 1
// 打印变量类型名称
int a = 41; // a是一个左值
class MyClass{};
MyClass myclass;
cout << "a:" << typeid(a).name() << endl; // typeid获取变量的类型信息,其中name是类型的名称
cout << "myclass:" << typeid(myclass).name() << endl; // 自定义类型名称包含.?AVMyClass@main@
// auto
cout << "auto:" << endl;
{
int &b = a; // b是a的引用
auto a1 = a; // a1是int
auto b1 = b; // b1是int
const int c = a, &d = c; // c是 const int, d是 const int&
cout << "a1:" << typeid(a1).name() << endl; // 输出a1是int
cout << "b:" << typeid(b).name() << endl; // 输出b是int
cout << "b1:" << typeid(b1).name() << endl; // 输出b1是int
cout << "c:" << typeid(c).name() << endl; // 输出c是int
}
// decltype
cout << "decltype:" << endl;
{
int &b = a; // b是a的引用
const int &c = a; // c是 const int&
int&& d = 1; // d是右值引用
cout << "a is_lvalue_reference:" << is_lvalue_reference<decltype(a)>::value << endl;// 0
cout << "b is_lvalue_reference:" << is_lvalue_reference<decltype(b)>::value << endl;// 1
cout << "c is_lvalue_reference:" << is_lvalue_reference<decltype(c)>::value << endl;// 1
cout << "d is_lvalue_reference:" << is_rvalue_reference<decltype(d)>::value << endl;// 1
}
return 0;
}

C++11 auto、decltype、is_reference、is_rvalue_reference/is_lvalue_reference、typeid_c++ auto referance-优快云博客

### 关于 C++ 引用折叠 引用折叠是 C++11 中引入的一个重要特性,用于处理模板编程中的复杂类型推导问题。当涉及到右值引用 `T&&` 和左值引用 `T&` 的组合时,可能会出现嵌套的引用形式(如 `T&&&` 或 `T&&&&`)。为了简化这种复杂的语法结构并使其更易于理解,C++ 定义了一组规则来决定最终的引用类型。 #### 引用折叠规则 以下是 C++ 中关于引用折叠的具体规则: 1. 如果两个引用类型被折叠在一起,则遵循以下原则: - **`T& &` 折叠成 `T&`**[^1]。 - **`T& &&` 折叠成 `T&`**。 - **`T&& &` 折叠成 `T&`**[^1]。 - **`T&& &&` 折叠成 `T&&`**[^1]。 2. 这些规则适用于任何涉及模板参数类型的上下文中,尤其是在完美转发机制中使用的 `std::forward<T>` 函数内部实现过程中。 #### 示例代码展示引用折叠的应用 下面通过一段代码演示引用折叠的实际效果以及其在模板函数中的应用: ```cpp #include <iostream> #include <type_traits> template<typename T> void test(T&& param) { std::cout << "Type of param is: " << typeid(param).name() << "\nIs lvalue reference? " << std::is_lvalue_reference<decltype(param)>::value << "\nIs rvalue reference? " << std::is_rvalue_reference<decltype(param)>::value << '\n'; } int main() { int x = 42; // 左值调用 test(x); // 输出显示 param 是左值引用 // 右值调用 test(42); // 输出显示 param 是右值引用 return 0; } ``` 在这段代码中,模板函数 `test` 接受一个通用引用 `T&&` 参数。由于引用折叠的存在,在不同情况下传入实际参数时会自动调整为合适的引用类型,从而支持完美的转发行为。 #### 解决引用折叠相关问题的关键点 对于开发者来说,理解和掌握引用折叠规则有助于编写更加灵活和高效的泛型代码。特别是在设计能够接受任意类型作为输入参数的接口时,利用好这一特性能有效减少不必要的拷贝操作,并提高程序运行效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值