C++模板定义中std::decay适用场景及两种max函数实现正确性对比
C++ std::decay使用场景与模板实现对比
两个版本的规范度判断
带std::decay的max_test版本更规范,原因如下:
第二个max_test_r版本存在严重的未定义行为风险:根据C++的decltype推导规则,当作用于左值表达式时,decltype会推导得到左值引用类型。比如传入两个int类型的左值参数时,a > b ? a : b是左值表达式,decltype推导结果为int&,这意味着函数会返回指向函数形参a或b的引用。但a、b是函数的按值传递形参,函数执行结束后就会被销毁,返回的引用会变成悬垂引用,调用方访问该返回值就会触发未定义行为。
而max_test中使用std::decay对推导类型做退化处理,会去掉类型的引用、顶层const/volatile修饰,最终得到值类型,和函数按值返回结果的语义完全匹配,没有悬垂引用风险。
std::decay的使用原则
不需要刻意避免使用std::decay,它是标准库提供的常用类型转换工具,只需要根据场景判断是否需要即可。
适合使用std::decay的场景
- 需要得到纯值类型的场景:比如按值返回的函数返回值类型推导,消除引用、cv修饰符带来的意外行为
- 模板参数类型匹配场景:比如做类型相等判断时,如果不需要考虑引用、cv修饰的差异,用
std::decay_t<T>处理后再判断,避免const int&和int被判为不同类型的问题 - 数组/函数类型退化场景:当你不需要保留数组的长度信息、不需要保留函数类型本身,希望将数组转为指针、函数转为函数指针时,用
std::decay可以统一处理
不适合使用std::decay的场景
- 语义需要保留引用的场景:比如实现返回容器元素引用的访问接口、需要返回左值引用支持链式调用的函数,就不能加decay
- 需要保留类型特殊属性的场景:当你需要保留类型的const/volatile修饰、数组长度、函数签名信息时,不要使用decay
内容的提问来源于stack exchange,提问作者jozoppi
相关产品推荐
相关产品推荐

