C++ decltype 关键字学习

本文深入探讨C++11中的decltype关键字,如何使用它确定表达式的类型,以及结合后置返回类型解决函数模板中类型推导的问题。通过具体示例,解释decltype在不同场景下的应用,并展示如何利用它简化模板函数的类型定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据我上一片博客的介绍–c++函数模板初探
我们可以用模板实现很多函数,也对c++函数模板有了初步的了解。

但是加入有下面这个情况:

template <class T1, class T2>
void ft (T1 &x, T2 &y)
{
	...
	?type? xpy = x+;
	...	
}

在这种情况下xpy应该是什么类型呢?由于不知道ft()将如何使用,因此无法预知这一点。正确的类型可能是T1、T2或者其他类型。假如又出现了重载运算符,这会让问题更加的复杂。

于是为了解决这个问题,c++11新增了关键字 decltype

我们可以这样使用:

int x;
decltype(x) y;//y的类型和x类型一致

除了上述这样写,我们也可以这样写:

decltype(x+y) xpy;
xpy = x+y;

通过这个关键字,我们可以把前面的代码修改成这样:

template <class T1, class T2>
void ft(T1 x, T2 y)
{
	...
	decltype(x+y) xpy = x+y;

	...
}

decltype比这些实例要复杂些。为了确定类型,编译器必须遍历一个核对表。假设有如下声明:

decltype (expression) var;

1.如果expression是一个没有用括号括起的标识符,则var的类型与该标识符类型相同,包括const等限定符

double x = 5.5;
double y = 7.9
double &rx = x;
const double *pd;
decltype(x) w; // w is type double 
decltype (rx) u = y; // u is type double &
decltype(pd) v; // v is type const double *

2.如果expression是一个函数调用,则var的类型与函数的返回类型相同:

long indeed(int)
decltype (indeed(3)) m; // is type int

这里并不会实际调用函数。编译器通过查看函数的原型来获悉返回类型,而无需实际调用函数。

3.加入expression是用括号括起来的标识符:

double xx = 4.4;
decltype((xx)) r2 = xx ; // r2 is double &
decltype(xx) w = xx; // w is double

括号并不会改变表达式的值和左值性。

4.如果前面都不满足,则var的类型与expression类型相同:

int j = 3;
int &k  = j;
int  &n = j;
decltype (j+6)i1; // i1 type int
decltype (100L) i2; // i2 type long
decltype (k+n) i3; // i3 type int

虽然k和n都是引用,是表达式k+n不是引用。
如果需要多次声明,可以结合使用typdefdecltype:

template <class T1, class T2>
void ft(T1 x, T2 y)
{
	typedef decltype (x+y) xytype;
	xytype xpy = x+y;
	xytype arr[10];
	xytype &rxy = arr[2]; // rxy a reference
}

还有一个问题是decltype没有办法解决的:

template <class T1, class T2>
?type? gt(T1 x, T2 y)
{
	return x+y;	
}

同样无法预知x和y相加得到的类型。看起来我们还可以用decltype,但是很不幸,这个时候还没有声明x和y,它们不在作用域内。**必须在声明参数后使用decltype。**为此,c++新增了一种声明和定义函数的语法。

double h(intx, float y);
可以用新增的语法编写成这个样子:
auto h(int x, float y) -> double;

这将返回类型移到了参数声明后面。->double被称为后置返回类型(trailing return type)。 其中auto是一个占位符,表示后置返回类型提供的类型。这是c++11的新增auto语法。这个语法也可以用于函数定义。

auto h (int x, float y) -> double
{/* function body*/};

通过结合使用这种语法和decltype,便可以给gt()指定返回类型。

template <class T1, class T2>
auto gt(T1x, T2 y)  ->decltype(x+y)
{
	return x+y;
}

现在,decltype在参数声明后面,因此x和y位于作用域内,可以使用它们。

### C++ 中 `decltype` 关键字的用法及其与 `auto` 和函数指针的关系 #### 1. `decltype` 的基本用法 `decltype` 是 C++11 引入的关键字,用于在编译时推导表达式的类型。它与 `auto` 类似,但用途更为广泛,特别是在复杂的模板编程中[^1]。以下是一个简单的示例: ```cpp int x = 42; decltype(x) y = x; // y 的类型为 int ``` `decltype` 不需要初始值来推导类型,只需一个表达式即可。这使得它在某些场景下比 `auto` 更加灵活[^2]。 #### 2. `decltype` 与 `auto` 的区别 虽然 `decltype` 和 `auto` 都用于类型推导,但它们之间存在显著差异: - `decltype` 主要用于查询表达式的类型,而 `auto` 主要用于自动推导变量的类型。 - `decltype` 不需要初始值来推导类型,而 `auto` 必须有初始值[^2]。 - `decltype` 通常用于类型别名、模板编程等复杂场景,而 `auto` 更适合于函数返回类型、循环变量等简单场景。 以下代码展示了两者的差异: ```cpp int a = 10; auto b = a; // b 的类型为 int decltype(a) c; // 错误:decltype 不需要初始值,但此处未初始化 decltype(a) d = a; // d 的类型为 int ``` #### 3. `decltype` 与函数指针结合使用 `decltype` 可以用于推导函数指针的类型。例如: ```cpp int add(int a, int b) { return a + b; } decltype(add) *funcPtr = add; // funcPtr 是指向 add 函数的指针 ``` 在此示例中,`decltype(add)` 推导出 `add` 函数的类型,并将其赋值给函数指针 `funcPtr`[^3]。 #### 4. `decltype` 与模板结合使用 `decltype` 常用于模板编程中,特别是在需要推导复杂表达式类型时。以下是一个示例: ```cpp template <typename T, typename U> auto multiply(T t, U u) -> decltype(t * u) { return t * u; } ``` 在这个例子中,`decltype(t * u)` 用于推导表达式 `t * u` 的类型,并将其作为函数的返回类型[^1]。 #### 5. `decltype` 与 `auto` 在函数参数中的结合使用 从 C++20 开始,`auto` 可以用作函数参数类型,此时可以结合 `decltype` 来进一步推导参数的类型。例如: ```cpp void printSize(auto x) { std::cout << sizeof(x) << std::endl; std::cout << typeid(decltype(x)).name() << std::endl; } ``` 在这个例子中,`auto` 自动推导出参数 `x` 的类型,而 `decltype(x)` 则用于获取其具体的类型信息[^3]。 #### 6. `decltype` 与运行时类型识别的区别 需要注意的是,`decltype` 用于编译时类型推导,而 `typeid` 用于运行时类型识别。两者的应用场景完全不同[^4]。例如: ```cpp int x = 42; std::cout << typeid(x).name() << std::endl; // 运行时类型识别 decltype(x) y = x; // 编译时类型推导 ``` ### 示例代码 以下是一个综合示例,展示 `decltype`、`auto` 和函数指针的结合使用: ```cpp #include <iostream> #include <typeinfo> // 普通函数 int add(int a, int b) { return a + b; } // 模板函数 template <typename T, typename U> auto multiply(T t, U u) -> decltype(t * u) { return t * u; } int main() { // 使用 decltype 推导函数指针类型 decltype(add) *funcPtr = add; std::cout << "Result of function pointer: " << funcPtr(3, 4) << std::endl; // 使用 auto 和 decltype 推导模板函数返回类型 auto result = multiply(5, 6); std::cout << "Result of template function: " << result << std::endl; // 使用 auto 和 decltype 推导变量类型 int x = 10; decltype(x) y = x; std::cout << "Type of y: " << typeid(y).name() << std::endl; return 0; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值