服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++函数模板:掌握返回类型推导的艺术

C++函数模板:掌握返回类型推导的艺术

2024-01-18 15:38coding日记 C/C++

在 C++ 中,当使用 auto 关键字来推导函数返回值的类型时,它会自动去除表达式中的引用(reference)和 const 限定符。这意味着,如果函数的返回类型原本是一个引用或 const 类型,使用 auto 推导后,返回值将会失去这些属性。

编译器推导返回类型

讨论 add() 函数模板的示例,让编译器推导返回值的类型确实是个好主意。然而,返回类型依赖于模板类型参数,那该如何实现呢?例如,考虑以下函数模板:

template <typename T1, typename T2>
RetType add(const T1& t1, const T2& t2) {
    return t1 + t2;
}

在这个示例中,RetType 应该是表达式 t1 + t2 的类型,但你无法知道这一点,因为你不知道 T1 和 T2 是什么。

C++函数模板:掌握返回类型推导的艺术

自动类型推导

自 C++14 起,你可以让编译器自动推导函数的返回类型。因此,你可以简单地将 add() 写成如下:

template <typename T1, typename T2>
auto add(const T1& t1, const T2& t2) {
    return t1 + t2;
}

在 C++ 中,当使用 auto 关键字来推导函数返回值的类型时,它会自动去除表达式中的引用(reference)和 const 限定符。这意味着,如果函数的返回类型原本是一个引用或 const 类型,使用 auto 推导后,返回值将会失去这些属性。例如,如果原本返回的是一个 const 引用,使用 auto 推导后,返回值将仅是一个值,而非引用,并且也不再是 const 类型。

对于某些函数来说,这种去除引用和 const 的行为是可以接受的。例如,在 add() 函数模板中,如果使用 auto,这通常没问题,因为 operator+(加法运算符)一般返回一个新的对象,而不是引用或 const 对象。

然而,在其他一些情况下,可能需要保留函数返回值的原始属性,比如其为引用或 const 类型。在这些情况下,简单地使用 auto 来推导返回类型可能就不够理想了。因此,需要使用其他方法(使用 decltype(auto) 的函数模板)来确保函数返回值的原始属性被正确保留。

auto 与 decltype 的区别

考虑以下非模板示例,了解 auto 和 decltype 之间的差异:

const std::string message { "Test" };
const std::string& getString() { return message; }

auto s1 { getString() }; // s1 是 string 类型,进行了拷贝
const auto& s2 { getString() }; // s2 是对常量的引用
decltype(getString()) s3 { getString() }; // s3 是 const string& 类型
decltype(auto) s4 { getString() }; // s4 也是 const string& 类型

使用 decltype(auto) 的函数模板

有了这些知识,我们可以使用 decltype(auto) 来编写我们的 add() 函数模板,以避免去除任何 const 和引用限定符:

template <typename T1, typename T2>
decltype(auto) add(const T1& t1, const T2& t2) {
    return t1 + t2;
}

C++14 之前的方法

在 C++14 之前,也就是在函数返回类型推导和 decltype(auto) 得到支持之前,问题是通过使用 decltype(expression) 来解决的,这是 C++11 引入的。例如,你可能会写出以下代码:

template <typename T1, typename T2>
decltype(t1 + t2) add(const T1& t1, const T2& t2) {
    return t1 + t2;
}

然而,这是错误的。你在原型行的开头使用了 t1 和 t2,但这些参数还未知。t1 和 t2 在到达参数列表末尾时才变得已知。

这个问题曾经通过替代函数语法解决。注意,在这种语法中,auto 用于原型行的开头,而实际的返回类型在参数列表之后指定(尾随返回类型);因此,参数的

名称(以及它们的类型,从而 t1 + t2 的类型)是已知的:

template<typename T1, typename T2>
auto add(const T1& t1, const T2& t2) -> decltype(t1 + t2) {
    return t1 + t2;
}

注意:现在 C++ 支持 auto 返回类型推导和 decltype(auto),建议使用这些机制,而不是替代函数语法。

C++20 的新特性

C++20 引入了一种简化的函数模板语法。再次回顾前面的 add() 函数模板。这里是推荐的版本:

template <typename T1, typename T2>
decltype(auto) add(const T1& t1, const T2& t2) {
    return t1 + t2;
}

看这个示例,为了指定一个简单的函数模板,语法显得相当冗长。使用简化的函数模板语法,可以更优雅地写成如下:

decltype(auto) add(const auto& t1, const auto& t2) {
    return t1 + t2;
}

使用这种语法,不再需要 template<> 规范来指定模板参数。相反,以前在实现中使用的 T1 和 T2 类型现在被指定为 auto。这种简化的语法只是语法糖;编译器会自动将这种简化实现转换为更长的原始代码。基本上,每个被指定为 auto 的函数参数都成为一个模板类型参数。

需要注意的两个问题

(1) 不同的模板类型参数:每个被指定为auto的参数都成为不同的模板类型参数。假设你有这样一个函数模板:

template <typename T>
decltype(auto) add(const T& t1, const T& t2) {
    return t1 + t2;
}

这个版本只有一个模板类型参数,而函数的两个参数 t1 和 t2 都是 const T& 类型。对于这样的函数模板,你不能使用简化语法,因为这将被转换为具有两个不同模板类型参数的函数模板。

(2) 无法显式使用推导类型:你不能在函数模板的实现中显式使用这些自动推导的类型,因为这些自动推导的类型没有名称。如果你需要这样做,你要么需要继续使用普通的函数模板语法,要么使用 decltype() 来确定类型。

// C++50 中的 auto 使用
auto auto(auto... args) {
    return (... + args);
}

原文地址:https://mp.weixin.qq.com/s?__biz=Mzg2NzY2NTUyMg==&mid=2247484856&idx=1&sn=6977b54034957d93d16a7c29b917e870

延伸 · 阅读

精彩推荐
  • C/C++C++模板之特化与偏特化详解

    C++模板之特化与偏特化详解

    这篇文章主要介绍了C++模板之特化与偏特化详解,本文讲解了什么是C++模板、模板特化、模板偏特化、特化与偏特化的调用顺序等内容,需要的朋友可以参考...

    果冻想4342021-02-05
  • C/C++简单讲解c++ vector

    简单讲解c++ vector

    这篇文章主要介绍了c++ vector的相关资料,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下...

    TONG9272021-09-28
  • C/C++Qt实现矩形大小任意缩放的示例代码

    Qt实现矩形大小任意缩放的示例代码

    这篇文章主要介绍了Qt如何实现在窗口上绘制任意大小的矩形,并且通过边角的拖曳按钮可改变矩形大小,感兴趣的小伙伴可以跟随小编一起学习一下...

    la_vie_est_belle10872022-12-20
  • C/C++可读可执行的C语言简历源文件

    可读可执行的C语言简历源文件

    这篇文章主要为大家家详细介绍了可读可执行的C语言简历源文件,感兴趣的小伙伴们可以参考一下...

    C语言教程网7722021-04-09
  • C/C++C++三元表达式详情

    C++三元表达式详情

    这篇文章主要介绍了C++三元表达式,文章围绕C++三元表达式的相关资料展开详细内容,需要的朋友可以参考一下,希望多你有所帮助...

    梁唐10122022-02-23
  • C/C++详解C++中变量的初始化规则

    详解C++中变量的初始化规则

    这篇文章详细介绍了关于C++中变量的初始化规则,C++如果不对变量初始化,可能会导致很多后果,所以学习C++变量初始化规则就很重要了,下面一起来看看...

    C++教程网9302021-04-15
  • C/C++C语言进阶可变参数列表

    C语言进阶可变参数列表

    这篇文章主要为大家介绍了C语言进阶可变参数列表的示例详解有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步...

    乔乔家的龙龙9452022-09-22
  • C/C++纯C语言:分治快速排序源码分享

    纯C语言:分治快速排序源码分享

    这篇文章主要介绍了分治快速排序源码,有需要的朋友可以参考一下...

    C语言教程网6902021-01-13