1350 字
7 分钟
07类型推导
2025-01-09

类型别名#

传统的方法:typedef

// wage是double的同义词
typedef double wage;
// salary是double的同义词,p是*double的同义词
typedef wage salary, * p;
//等价于
typedef double* p;

当使用const来修饰typedef别名时,是直接修饰别名数据本身。

typedef char * pstring;
// 等价于 char * const str (常量指针)
const pstring str = "hello";
str++; // 报错
// 等价于 char* const * str (指向常量指针的指针)
const pstring * str;

C++11的方法#

别名声明(alias declaration)

// 把等号右边的类型,取名为等号左边的别名
using int64_t = long long

Auto自动推导#

  1. auto会自动推导指针类型。
    1. 底层const(数据部分const)会保留,顶层const会忽略。
  2. 引用类型数据会自动推导引用的数据类型。
  3. auto + & 表示声明引用类型。

auto后面可以使用逗号,定义多个变量,但是auto推导只会出现一个类型,必须保证类型相同。

auto int i = 1, pi = 3.14; //后面是double和int不同。

decltype类型指示符#

C++11

有时会遇到这种情况:希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。

为了满足这一要求,C++11新标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值:

decltype(f()) sum = x; //sum的类型就是函数f的返回值的类型

编译器并不实际调用函数f,而是使用当调用发生时f的返回值类型作为sum的类型。换句话说,编译器为sum指定的类型是什么呢?就是假如f被调用的话将会返回的那个类型。

decltype处理顶层const和引用的方式与auto有些许不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内):

const int ci = 0, &cj = ci;
//x是const int类型
decltype(ci) x = 0;
//y是一个const int&类型,y绑定到x
decltype(cj) y = x;
//错误,z是一个引用,引用必须初始化
//decltype(cj) z;

因为cj是一个引用,decltype(cj)的结果就是引用类型,因此作为引用的z必须被初始化。

需要指出的是,引用从来都作为其所指对象的同义词出现,只有用在decltype处是一个例外。

decltype和引用#

如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。

有些表达式将向decltype返回一个引用类型。

一般来说当这种情况发生时,意味着该表达式的结果对象能作为一条赋值语句的左值:

{
//decltype的结果可以是引用各类型
int i = 42, *p = &i, &r = i;
//正确,假发的结果是int,因此b是一个未初始化的int
decltype(r + 0) b;
//错误,c是int&,必须初始化
//decltype(*p) c;
}

因为r是一个引用,因此decltype(r)的结果是引用类型。

如果想让结果类型是r所指的类型,可以把r作为表达式的一部分,如r+0,显然这个表达式的结果将是一个具体值而非一个引用。

另一方面,如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。

因此,decltype(*p)的结果类型就是int&,而非intdecltypeauto的另一处重要区别是,decltype的结果类型与表达式形式密切相关。

有一种情况需要特别注意:对于decltype所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同。

如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型;

如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型:

//decltype的表达式如果加上了括号的变量,结果就是引用
//错误,d是int&,必须初始化
//decltype((i)) d;
//正确,e是一个未被初始化的int类型值
decltype(r) e = i;

切记:decltype((variable))注意是双层括号)的结果永远是引用,而decltype(variable)结果只有当variable本身就是一个引用时才是引用。

工作中的应用#

工作中会利用autodecltype配合使用,结合模板做类型推导返回动态类型,比如我们在并发编程系列课程中封装提交任务

template <class F, class... Args>
auto commit(F&& f, Args&&... args) ->
std::future<decltype(std::forward<F>(f)(std::forward<Args>(args)...))> {
using RetType = decltype(std::forward<F>(f)(std::forward<Args>(args)...));
if (stop_.load())
return std::future<RetType>{};
auto task = std::make_shared<std::packaged_task<RetType()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<RetType> ret = task->get_future();
{
std::lock_guard<std::mutex> cv_mt(cv_mt_);
tasks_.emplace([task] { (*task)(); });
}
cv_lock_.notify_one();
return ret;
}

这段代码大家要学习模板,以及万能引用后才能完全吸收,我们留个伏笔,以后的剧情中会触发。

07类型推导
https://chrisnake11.github.io/blog/posts/coding/c基础/07类型推导/
作者
Zheyv
发布于
2025-01-09
许可协议
CC BY-NC-SA 4.0