现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34199 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

37|参数传递的正确方法和模板的二进制膨胀

抽取与模板参数无关的方法到非模板基类
使用指针或 span 替换数组参数
C++20 函数模板参数声明
泛型 lambda 表达式
变量声明
使用值方式传参
使用指针传参
使用 const 左值引用
使用值传参
同时被读和写的参数,常为序列对象
函数来写的参数,使用引用或指针
常见,用于函数使用的参数
[2] Arthur O’Dwyer, “Don’t blindly prefer emplace_back to push_back
[1] Arthur O’Dwyer, “‘Universal reference’ or ‘forward reference’?”
直接使用 T 的后果
try_decayremove_reference_t 的使用原因
unique_ptr 参数的正确写法
灵活且小巧的代码产出
合适的引用方式和退化使用
通过公共基类消减二进制膨胀
通过退化消减二进制膨胀
模板带来的方便与代码膨胀
通过退化消减特化
使用 const 引用或按值传参
特化和二进制代码膨胀
引用坍缩和类型推导
auto&& 的使用
make_uniquemake_sharedemplace 等使用场景
用于未知数量和类型的参数传递
不可选,移动友好,需要拷贝
可选
不可选,默认
不可选,内置类型或小对象
出入参
出参
入参
参考资料
课后思考
内容小结
模板的二进制膨胀
避免不必要的转发引用
转发引用的问题
转发引用
入参的传递规则
参数传递的方式
参数传递的正确方法和模板的二进制膨胀

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
上一讲我们讨论的视图类型的对象,通常和内置类型的对象一样,是使用传值的方式来进行传参的。这种方式非常简单,也是比较推荐的 C++ 的做法,但这种方式存在对对象类型的限制。在对象比较大的时候,或者可能比较大的时候,按值传参就可能有性能问题。这包括了大部分的函数模板,除非你能预知用来实例化模板的参数。此外,还有很多对象可能是不可复制、甚至不可移动的,显然,这些对象你也不可能按值传参。此时,你就只能使用引用或指针来传参了。

参数传递的方式

函数的参数有入参、出参和出入参之分。入参是最常见的情况,意味着一个参数是让函数来使用的。出参表示一个参数是函数来写的,它必须是一个引用或指针,在现代 C++ 里已经较少推荐,因为返回对象(包括结构体、pairtuple 等)往往可导致更加清晰、更加安全、同时性能也不下降的代码。出入参是一种中间情况,参数会被函数同时读和写。它也是引用或指针,常常是一个序列的对象(如 vectorstring),里面本来就有内容,并在函数执行的过程中让函数继续往里添加内容。
对于现代 C++,非可选的出参和出入参通常使用引用方式,这样的代码写起来会更加方便。而可选的出参和出入参则一般使用指针方式,可以用空指针表示这个参数不被使用。而入参的情况就复杂多了:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入讨论了C++参数传递的正确方法和模板的二进制膨胀问题。首先介绍了函数参数的入参、出参和出入参的区别,以及现代C++中推荐的参数传递方式。接着详细讨论了不同情况下的参数传递方式,包括不可选参数、大对象、移动友好的参数等。文章还介绍了转发引用和auto&&的使用方法,以及转发引用可能存在的问题。此外,通过举例和技术原理深入探讨了函数参数传递的最佳实践和模板二进制膨胀的问题。对于C++开发者来说,本文提供了深入的技术细节和实用的建议,有助于他们更好地理解和应用参数传递的最佳实践。文章还讨论了通过退化和公共基类消减二进制膨胀的方法。总的来说,本文为读者提供了深入的技术细节和实用的建议,有助于他们更好地理解和应用参数传递的最佳实践,以及解决模板二进制膨胀的问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(3)

  • 最新
  • 精选
  • 罗 乾 林
    课后思考: 1.const std::unique_ptr<A> & 2.如果传入参数为数组,T类型推导将为数组的引用,is_array_v<T>结果为false,因为此时T为引用. remove_extent_t<T>结果仍然是数组的引用,span这里编译不通过

    作者回复: 1. 参考第 41 讲。一般不建议用 const unique_ptr& 传参。 2. 正确。

    2023-04-21归属地:上海
    3
    1
  • 李云龙
    由于unique_ptr不支持复制,那么使用 unique_ptr<T>& 作为函数的传入传出参数比较合适。

    作者回复: 请直接参考第 41 讲。

    2023-11-19归属地:美国
  • coming
    #include <span> int main() { auto lambda = [](const auto& x, const auto& y) { // 处理并返回 }; int n; long long lln; std::span<const int> sp; lambda(n, lln); lambda(lln, n); lambda(n, 1); lambda(n, sp[0]); lambda(sp[0], lln); return 0; } 我使用https://cppinsights.io/s/a77543e0, 确认是实例化了三个 #ifdef INSIGHTS_USE_TEMPLATE template<> inline /*constexpr */ void operator()<int, long long>(const int & x, const long long & y) const { } #endif #ifdef INSIGHTS_USE_TEMPLATE template<> inline /*constexpr */ void operator()<long long, int>(const long long & x, const int & y) const { } #endif #ifdef INSIGHTS_USE_TEMPLATE template<> inline /*constexpr */ void operator()<int, int>(const int & x, const int & y) const { } #endif 老师能说下, 哪一讲,讲了这个推导规则吗? 我有点懵

    作者回复: 泛型lambda表达式在第16讲介绍,不过当时确实讲得比较简单。需要记住的是 它本质上是具有 operator() 成员函数模板的类的函数对象。对于这个例子,相当于如下的 operator(): template <typename T, typename U> auto operator()(const T& x, const U& y) { … } 然后就是普通的模板参数匹配和推导了。这样是不是好理解一点?

    2023-08-14归属地:上海
    3
收起评论
显示
设置
留言
3
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部