【C++进阶知识】01 - auto、typeid、decltype

1. auto

1.1 auto的使用场景

(1)优化map的查找

std::map<std::string, int> NewMap = {
	{"one", 1}, {"two", 2}, {"three", 3}
};
// C++17可支持,使用auto遍历map
for (auto [key, val] : NewMap) 
{
	std::cout << val << std::endl;
}

(2)结构体/类的拆解

class MyStruct
{
public:
	int id;
	std::string name;
};
int main()
{
	MyStruct TestStruct(1, "Hello");
	// 用auto对类或者结构体里面的变量进行性拆解
	auto [x, y] = TestStruct;
	std::cout << x << " , " << y << std::endl;
}

(3)使用类似于泛型编程的作用

针对于函数返回值

/** 
 * auto:函数返回值推导
 * 注意:返回值类型一定要一致否则无法推导
 */
auto sum(long x, long y)
{
	return x + y;
}

针对于lambda表达式

/**
 * auto:lambda表达式完全泛型
 */
auto l1 = [](auto x, auto y)
{
	return x + y;
};
// lambda返回值引用的方法
auto l2 = [](int& i) -> auto& 
{
	return i;
};

针对于非类型模板

/** 
 * auto:非类型模板的auto类型自动推导
 * 注意:auto无法推导double类型,因为double会损失精度
 */
template<auto N>
void f()
{
	std::cout << N << std::endl;
}
int main()
{
	f<5>();
	f<'x'>;
	f<5.0>; // 错误,用auto作为模板类型推导不能使用double
}

(4)万能引用

int i =10;
auto&& x = i; // i为左值,auto推导为int&,即x为左值引用int&
auto&& y = 10; // 10为右值,auto推导为int,即y为右值引用int&&

1.2 理论部分

auto的注意事项:
(1)auto会推导类型,但引用不是类型,因此会忽略引用。
(2)auto会忽略值类型的const,而保留修饰指向对象的const,即会保留指针的const;如果需要const,使用auto&即会保留原有值对应的const;也可以使用const auto。
(3)auto不会影响编译速度,甚至会加快编译速度。

2. typeid

2.1 使用场景

int x = 0;
std::cout << typeid(x).name() << std::endl;

2.2 理论部分

typeid的注意事项:
(1)typeid返回值的type_info中的name所返回类型名在C++中没有明确的规定,不同版本输出会不一样。
(2)typeid的返回值std::type_info是一个左值,其生命周期一直到程序生命周期结束。
(3)std::type_info删除了复制构造函数,若想保存std::type_info需要引用或指针。
(4)typeid会忽略const,也就是typeid(const T) == typeid(T)。

3. decltype

3.1 decltype使用场景

(1)优化函数模板的返回类型

/** 
 * 使用decltype对返回值类型进行限定
 * 在C++14后auto已经能自动推导,并不需要 -> decltype,但auto返回值类型而不返回引用
 */
template<class T1, class T2>
auto sun(T1 x, T2 y) -> decltype(x + y)
{
	return x + y;
}
/** 若想返回引用就一定要使用decltype */
template<class T>
auto sun(T& x) -> decltype(x)
{
	return x;
}

(2)模板前置返回值的推导类型

/** 使用static_cast进行强制转化 */
template<class T1, class T2>
decltype(*static_cast<T1*>(nullptr) + *static_cast<T2*>(nullptr)) sum1(T1 t1, T2 t2)
{
	return t1 + t2;
}

/** 使用std::declval进行类型对象的获取 */
template<class T1, class T2>
decltype(std::declval<T1> + std::declval<T2>) sum2(T1 t1, T2 t2)
{
	return t1 + t2;
}

decltype(auto):在使用上完全和auto一致,只是用decltype的推导规则。同时注意decltype(auto)只能单独声明,不能结合指针、引用或者cv限定。

/** 使用decltype(auto),优化返回引用 */
template<class T>
decltype(auto) sun(T& x)
{
	return x;
}

/** 使用decltype(auto),优化非类型模板的auto类型自动推导 */
template<decltype(auto) N>
void f()
{
	std::cout << N << std::endl;
}

3.2 理论部分

decltype在使用上与typeof()完全一致,decltype极大的加强了C++的泛型能力。

注意:使用decltype推导表达式,主要看表达式本身返回一个左值引用还是值类型。

struct MyStruct
{
	double x;
};

int main()
{
	const MyStruct* TestStruct = new MyStruct();
	int i;
	int* j;
	int a[10];
	decltype(i); // 推导表达式的类型,为int
	decltype((TestStruct->x)); // 推导()表达式的类型,应该是一个引用,类型为const double& 
	decltype(i = 0); // 推导表达式的类型,为int&
	decltype(0, i); // 推导逗号表达式,为int&
	decltype(i, 0); // 推导逗号表达式,为int
	decltype(i++); // 返回亡值,推导类型为int
	decltype(++i); // 推导类型为int&
	decltype(*j); // 推导类型为int&
	decltype(a[5]); // 推导类型为int&
};

遵从以下规则:
(1)当表达式的值类别为亡值,会返回T&&;
(2)当表达式的值类别是左值,且该实参是没有括号的标识表达式,则会返回该实参的类型即T;
(3)当表达式的值类别是左值,且该实参不是是没有括号的标识表达式,则会返回T&;
(4)当表达式的值类别是纯右值,会返回T。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值