- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
右值引用 移动语义 完美转发具体是什么,就不说了,网上一搜一大堆,主要介绍下std::move和std::forward 。
查下源码,gcc版本:gcc version 7.3.0 (GCC),grep -r "forward(" /usr/include/c++/7.3.0/bits/,move和forward都在/usr/include/c++/7.3.0/bits/move.h文件中,源码如下:
/** 92 * @brief Convert a value to an rvalue. 93 * @param __t A thing of arbitrary type. 94 * @return The parameter cast to an rvalue-reference to allow moving it. 95 */ 96 template<typename _Tp> 97 constexpr typename std::remove_reference<_Tp>::type&& 98 move(_Tp&& __t) noexcept 99 { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } /** 66 * @brief Forward an lvalue. 67 * @return The parameter cast to the specified type. 68 * 69 * This function is used to implement "perfect forwarding". 70 */ 71 template<typename _Tp> 72 constexpr _Tp&& 73 forward(typename std::remove_reference<_Tp>::type& __t) noexcept 74 { return static_cast<_Tp&&>(__t); } 75 76 /** 77 * @brief Forward an rvalue. 78 * @return The parameter cast to the specified type. 79 * 80 * This function is used to implement "perfect forwarding". 81 */ 82 template<typename _Tp> 83 constexpr _Tp&& 84 forward(typename std::remove_reference<_Tp>::type&& __t) noexcept 85 { 86 static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument" 87 " substituting _Tp is an lvalue reference type"); 88 return static_cast<_Tp&&>(__t); 89 }
本质就是强制类型转换,move并不进行所谓的“移动” 。
用c++14实现一下,更简单,如下:
// C++14 version of std::move template<typename _Tp> constexpr decltype(auto) move(_Tp&& __t) noexcept { return static_cast<std::remove_reference_t<_Tp>&&>(__t); } // C++14 version of std::forward for lvalues template<typename _Tp> constexpr decltype(auto) forward(std::remove_reference_t<_Tp>& __t) noexcept { return static_cast<_Tp&&>(__t); } // C++14 version of std::forward for rvalues template<typename _Tp> constexpr decltype(auto) forward(std::remove_reference_t<_Tp>&& __t) noexcept { static_assert(!std::is_lvalue_reference_v<_Tp>, "template argument substituting _Tp is an lvalue reference type"); return static_cast<_Tp&&>(__t); }
写了一个测试程序,如下:
#include <iostream> #include <utility> // for std::move, std::forward #include <type_traits> // for remove_reference_t, is_lvalue_reference_v // C++14 version of std::move template<typename _Tp> constexpr decltype(auto) move(_Tp&& __t) noexcept { return static_cast<std::remove_reference_t<_Tp>&&>(__t); } // C++14 version of std::forward for lvalues template<typename _Tp> constexpr decltype(auto) forward(std::remove_reference_t<_Tp>& __t) noexcept { return static_cast<_Tp&&>(__t); } // C++14 version of std::forward for rvalues template<typename _Tp> constexpr decltype(auto) forward(std::remove_reference_t<_Tp>&& __t) noexcept { static_assert(!std::is_lvalue_reference_v<_Tp>, "template argument substituting _Tp is an lvalue reference type"); return static_cast<_Tp&&>(__t); } // Test class with move and copy constructors class Widget { public: Widget() { std::cout << "Widget default constructor\n"; } Widget(const Widget&) { std::cout << "Widget copy constructor\n"; } Widget(Widget&&) noexcept { std::cout << "Widget move constructor\n"; } }; // Function to test std::forward template <typename T> void forward_test(T&& arg) { Widget w = std::forward<T>(arg); } int main() { // Test std::move Widget widget1; std::cout << "Using std::move:\n"; Widget widget2 = std::move(widget1); // Should call move constructor // Test std::forward with lvalue std::cout << "\nUsing std::forward with lvalue:\n"; Widget widget3; forward_test(widget3); // Should call copy constructor // Test std::forward with rvalue std::cout << "\nUsing std::forward with rvalue:\n"; forward_test(Widget()); // Should call move constructor return 0; }
因为is_lvalue_reference_v c++17才支持,所以编译:g++ test_move_forward.cpp -o test_move_forward -std=c++17 。
有个全局的names,需要定义两个函数,一个是函数模板用的万能引用,一个函数的参数是普通的int(通过id检索到name,省略此实现),代码如下:
#include <iostream> #include <type_traits> #include <utility> // for std::forward #include <unordered_set> // 全局数据结构 std::unordered_set<std::string> names; // 日志函数 void log(const char* message) { std::cout << "Log: " << message << std::endl; } // 模板版本 template<typename T> void logAndAdd(T&& name) { log("logAndAdd (perfect forwarding)"); names.emplace(std::forward<T>(name)); } void logAndAdd(int idx) { log("logAndAdd (int version)"); // 处理 int 类型的逻辑 } int main() { std::string name = "Alice"; int idx = 42; // 测试左值 logAndAdd(name); // 应该调用模板版本 // 测试右值 logAndAdd(std::string("Bob")); // 应该调用模板版本 // 测试 int 类型 logAndAdd(idx); // 测试 short 类型 short idx2 = 222; logAndAdd(idx2); return 0; }
上面的代码,没有测试 short 类型的那两行代码,是没问题的,但测试 short 类型的会匹配到完美转发那个函数,下面先用标签分发解决一下,代码如下:
#include <iostream> #include <type_traits> #include <unordered_set> #include <chrono> #include <utility> // for std::forward, std::move> #include <string> // 全局数据结构 std::unordered_set<std::string> names; // 日志函数 void log(const char* message) { auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); std::cout << "Log [" << std::ctime(&time) << "]: " << message << std::endl; } // 完美转发版本 template<typename T> auto logAndAddImpl(T&& name) -> std::enable_if_t< !std::is_convertible_v<T, int>, void > { log("logAndAdd (perfect forwarding)"); names.emplace(std::forward<T>(name)); } // 普通版本,专门处理 int 类型及其可隐式转换为 int 的类型 void logAndAddImpl(int idx) { log("logAndAdd (int version)"); // 处理 int 类型的逻辑 // 例如,将 int 转换为字符串并添加到集合中 names.insert(std::to_string(idx)); } // 分发函数 template<typename T> void logAndAdd(T&& name) { if constexpr (std::is_convertible_v<T, int>) { logAndAddImpl(static_cast<int>(std::forward<T>(name))); } else { logAndAddImpl(std::forward<T>(name)); } } // 额外的非模板版本,专门处理 int 类型 void logAndAdd(int idx) { logAndAddImpl(idx); } int main() { std::string name = "Alice"; int idx = 42; short idx2 = 222; // 测试左值 std::cout << "Testing lvalue:\n"; logAndAdd(name); // 应该调用完美转发版本 // 测试右值 std::cout << "\nTesting rvalue:\n"; logAndAdd(std::string("Bob")); // 应该调用完美转发版本 // 测试 int 类型 std::cout << "\nTesting int type:\n"; logAndAdd(idx); // 应该调用普通版本 // 测试 short 类型 std::cout << "\nTesting short type:\n"; logAndAdd(idx2); // 应该调用普通版本 // 打印全局数据结构中的名字 std::cout << "\nNames in the global set:\n"; for (const auto& name : names) { std::cout << name << std::endl; } return 0; }
代码如下:
#include <iostream> #include <type_traits> #include <unordered_set> #include <chrono> #include <utility> // for std::forward, std::move> #include <string> // 全局数据结构 std::unordered_set<std::string> names; // 日志函数 void log(const char* message) { auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); std::cout << "Log [" << std::ctime(&time) << "]: " << message << std::endl; } // 完美转发版本 template<typename T> auto logAndAdd(T&& name) -> std::enable_if_t< !std::is_convertible_v<T, int>, void > { log("logAndAdd (perfect forwarding)"); names.emplace(std::forward<T>(name)); } // 普通版本,专门处理 int 类型及其可隐式转换为 int 的类型 template<typename T> auto logAndAdd(T&& idx) -> std::enable_if_t< std::is_convertible_v<T, int>, void > { log("logAndAdd (int version)"); // 处理 int 类型的逻辑 // 例如,将 int 转换为字符串并添加到集合中 names.insert(std::to_string(static_cast<int>(idx))); } // 额外的非模板版本,专门处理 int 类型 void logAndAdd(int idx) { log("logAndAdd (int version)"); names.insert(std::to_string(idx)); } int main() { std::string name = "Alice"; int idx = 42; short idx2 = 222; // 测试左值 std::cout << "Testing lvalue:\n"; logAndAdd(name); // 应该调用完美转发版本 // 测试右值 std::cout << "\nTesting rvalue:\n"; logAndAdd(std::string("Bob")); // 应该调用完美转发版本 // 测试 int 类型 std::cout << "\nTesting int type:\n"; logAndAdd(idx); // 应该调用普通版本 // 测试 short 类型 std::cout << "\nTesting short type:\n"; logAndAdd(idx2); // 应该调用普通版本 // 打印全局数据结构中的名字 std::cout << "\nNames in the global set:\n"; for (const auto& name : names) { std::cout << name << std::endl; } return 0; }
还有一种方式模板特化,就不写代码了,写的脑壳疼 。
一入模板深似海,推荐两本书:Effective Modern C++,C++ Templates,有大佬有好的书,可以评论区推荐,感谢 。
。
最后此篇关于浅谈右值引用移动语义完美转发std::movestd::forward,窥探模板元编程的一角的文章就讲到这里了,如果你想了解更多关于浅谈右值引用移动语义完美转发std::movestd::forward,窥探模板元编程的一角的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
为了加速测试字谜字符串的快速输出行为,我 came up with基于质数的哈希方案——尽管它看起来像 I wasn't the first . 基本思想是将字母映射到素数,并计算这些素数的乘积。字母
我使用 Perfect Framework 创建了一个 Swift 3.0 服务器。一切都按预期进行得很好,但我正在尝试了解是否有更好的方法来做一些事情。 来自 iOS 背景,我知道总是在不同的线程中
我有一个固定大小的正方形 div,希望使用 CSS 在其中放置任意大小的图像,以便它在水平和垂直方向上都居中。横向很容易: .container { text-align: center } 对于垂直
程序员离不开终端,配置一个好看又好用的终端,可以提高工作效率. 本篇文章记录了使用 Oh My Zsh + PowerLevel9k + zsh插件 快速配置Ubuntu下默认终端的过程. 我们在
在请求处理程序中,处理例如获取 https://example.com/collections/1或 POSThttp://0.0.0.0:8080/collections 如何获取服务器地址 htt
我正在使用 perfect 和 SQLite司机和StORM作为连接器。我可以一一保存(创建)多行。为了使其更快,我想一次创建多行,我该怎么做? 最佳答案 从完美的 SQLite-StORM 和 Pe
这是我在这里的第一篇文章,所以我希望我提供所有正确的信息。 我目前正在开发一个简单的菜单应用程序,它有一个按钮控制数组(使用 MSDN 建议的控制数组的变通方法),我很难重新调整表单大小和将按钮居中。
在 androidplot XYPlot 中,如果您有较大的值(许多数字)和/或较大的字体大小,则 Y 轴上的刻度标签会被剪裁。这个(以及 X 轴上的类似问题)之前已经在这些问题中讨论过: Range
注意:我遗漏了不相关的代码 所以我目前正在研究 CCC 1996 P1,这个问题的全部目的是能够计算一个整数输入是完美数、不足数还是充数。我上面列出的代码可以工作,但是我认为它太慢了。该代码会迭代每个
我需要什么 我需要一个产生双射输出的算法。我有一个 31 位输入,需要一个伪随机 31 位输出。 我考虑过的 CRC 在其位宽内是双射的。 我查看了 Google 并找到了多项式,但找不到表格或算法。
我在 Ubuntu 14.04.1、clang-3.8 上使用 PerfectSwift我使用的是 Perfect,一切正常,但现在,我不能再编译了(但它可以在我的 mac 上编译) 错误日志是 /h
如果您对分表有以下痛点那么不妨试试我这边开源的框架sharding-core ,是否需要无感知使用分表组件,是否需要支持abp,是否需要支持自定义分表规则,是否需要支持自定义分表键,是否需要支持特定
我正在尝试确定我的 crc 与“ 理想 ”32 位 crc 的比较。 因此,我运行我的 crc 超过 100 万个完全随机的数据样本并收集了碰撞数量,我想将此数字与我可以从“ 理想 ”crc 中预期的
我正在开发一个项目,需要验证我的 URL,并偶然发现了以下正则表达式模式; /(((http|ftp|https):\/{2})+(([0-9a-z_-]+\.)+(aero|asia|biz|cat
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 4 年前。 Improve
我正在创建一个需要居中于中间的圆形网站。背景由围绕中心图像的圆圈组成。每当我以全屏(F11 快捷键)查看我的网站时,无论我的屏幕分辨率如何,它都完美居中。 如果我在没有全屏显示的情况下查看我的网站,我
所以我有一个网站,在开发人员工具中测试响应能力时看起来很棒,但在 iPhone 本身上实际测试时却没有居中并且看起来有些破烂。 什么会导致这种情况,如果我无法使用 iPhone(在我的 android
我有一个内部类,它扩展了 AbstractTableModel。 import javax.swing.table.AbstractTableModel; public class MyClass e
所以我正在使用 Perfect 服务器开发一个将值返回给客户端的应用程序。目前,它需要从另一个 API 下载一些数据,对其进行处理,然后将其发送给客户端。 然而,出于某种原因,它在 OSX 中编译良好
我有一些 CSS 按钮。 “按钮”效果是通过在 anchor 标记中使用固定大小的 元素来完成的,并且 css 规则以 a span:active 、 a span:hover 的形式显示按钮状态。
我是一名优秀的程序员,十分优秀!