C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?

本文主要是介绍C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

重载函数的调用优先级问题非常?疼,但是正如Nicolai Josuttis所说:C++允许你把性能追求到极至,但这是有代价的。

(午夜梦回的时候,我经常问自己这代价是不是太过高昂了?)

看下面的简单例子

struct X {};void foo(const X &) {std::cout << "const X &\n";
}auto bar() {return X{};
}

foo没有重载,只接受“传统“的参数类型const &

还有main中几种调用情况的打印

int main() {const auto out = [width=20, &os=std::cout](const char * const tag){os << std::setw(width) << tag << ' ';};auto x = X{};const auto cx = X{};out("foo(x)");foo(x);out("foo(cx)");foo(cx);out("foo(X{})");foo(X{});out("foo(bar())");foo(bar());out("foo(std::move(x))");foo(std::move(x));
}

程序的输出是

              foo(x) const X &foo(cx) const X &foo(X{}) const X &foo(bar()) const X &foo(std::move(x)) const X &

没什么值得吃惊的,我们然后再加一个重载

void foo(X &&) {std::cout << "X &&\n";
}

然后输出变成了,

              foo(x) const X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

因为foo(x)foo(cx)中,参数都是lvalue,所以匹配foo(const &),然后X{}bar()std::move(x)都是rvalue,所以匹配foo(X &&)

我们再加一个perfect forwarding

template <typename T, typename = std::enable_if_t<std::is_constructible_v<X, T>>>
void foo(T &&) {std::cout << "T &&\n";
}

然后输出变成了

              foo(x) T &&foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

foo(x)的匹配从foo(const &)变成了模版??!

这是因为foo(T&&)这里能够匹配一切引用,x是非const类型,所以相比foo(const &)来说,foo(T&&)实例化的foo(&),对foo(x)来说是更精确的匹配

我们可以进一步验证以下,增加一个重载

void foo(X &) {std::cout << "X &\n";
}

输出变成了

              foo(x) X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&

此时,foo(x)优先匹配了foo(&),而不是模版

这篇关于C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023461

相关文章

Java调用DeepSeek API的8个高频坑与解决方法

《Java调用DeepSeekAPI的8个高频坑与解决方法》现在大模型开发特别火,DeepSeek因为中文理解好、反应快、还便宜,不少Java开发者都用它,本文整理了最常踩的8个坑,希望对... 目录引言一、坑 1:Token 过期未处理,鉴权异常引发服务中断问题本质典型错误代码解决方案:实现 Token

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C# List.Sort四种重载总结

《C#List.Sort四种重载总结》本文详细分析了C#中List.Sort()方法的四种重载形式及其实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录1. Sort方法的四种重载2. 具体使用- List.Sort();- IComparable

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.