constexpr与std::is_same_v碰撞会产生什么火花?

2024-03-30 05:20

本文主要是介绍constexpr与std::is_same_v碰撞会产生什么火花?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 只编译会用到的if分支

示例代码一中,checkType_v1checkType_v2两个函数的区别就是if的条件里一个加了constexpr一个没加,加与不加从结果来看都一样,那在编译时和运行时各有什么区别呢?

示例代码一test_01.cpp

// g++  test_01.cpp  -std=c++17#include <iostream>
#include <type_traits>template<class T>
void checkType_v1(T){if constexpr (std::is_same_v<T, int>){std::cout << "Input is an int.\n";}else if constexpr (std::is_same_v<T, float>){std::cout << "Input is a float.\n";}else if constexpr (std::is_same_v<T, double>){std::cout << "Input is a double.\n";}else{std::cout << "Unsupported type!\n";}
}template<class T>
void checkType_v2(T){if (std::is_same_v<T, int>){std::cout << "Input is an int.\n";}else if (std::is_same_v<T, float>){std::cout << "Input is a float.\n";}else if (std::is_same_v<T, double>){std::cout << "Input is a double.\n";}else{std::cout << "Unsupported type!\n";}
}int main(){checkType_v1(4);   // Input is an int.checkType_v1(4.f); // Input is a float.checkType_v1(4.0); // Input is a double.checkType_v1('A'); // Unsupported type!checkType_v2(4);   // Input is an int.checkType_v2(4.f); // Input is a float.checkType_v2(4.0); // Input is a double.checkType_v2('A'); // Unsupported type!    
}

【来自C++大咖吴老师的解答】如果你要调用一个只接受某种类型的函数,那就必须用 if constexpr。此外,用 if constexpr 条件判断是编译是做出的,没用到的分支完全不会在某个类型的特化里产生二进制代码。

举例说明,也就是说针对checkType_v1的版本,假设调用它的时候传入的是int类型的参数,那么编译的二进制文件中只有代码里的第一个分支的实现。而checkType_v2的版本的二进制文件中是有整个函数的实现。

这么做的目的有如下三个(其中第三个最重要):

  1. 降低运行时的判断时间;
  2. 减少编译后二进制文件的大小;
  3. 【来自C++大咖吴老师的解答】但最重要的是,有些情况下你对特定类型要走的分支在其他类型的情况下可能完全编译不通过!比如,vector可以reservedeque不可以;deque可以push_frontvector不可以。

2. 验证上面第3点

示例代码二test_02.cpp

// g++  test_02.cpp  -std=c++17
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <vector>
#include <set>
#include <deque>template<class Container>
void expandContainer(Container& container, int val){if constexpr (std::is_same_v<Container, std::vector<int>>){container.push_back(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "vector number added.\n";}else if constexpr (std::is_same_v<Container, std::deque<int>>){container.push_front(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "deque number added.\n";}else{container.insert(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "Other container number added.\n";}
}int main(){std::vector<int> vec{1,2,3};expandContainer(vec,100);     // 1, 2, 3, 100, vector number added.std::deque<int> deq{4,5,6};expandContainer(deq, 200);    // 200, 4, 5, 6, deque number added.std::set<int> aset{7,8,9};expandContainer(aset, 300);   // 7, 8, 9, 300, Other container number added.

假如去掉constexpr,如示例代码三test_03.cpp

#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <vector>
#include <set>
#include <deque>template<class Container>
void expandContainer(Container& container, int val){if constexpr (std::is_same_v<Container, std::vector<int>>){container.push_back(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "vector number added.\n";}else if /*constexpr*/ (std::is_same_v<Container, std::deque<int>>){container.push_front(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "deque number added.\n";}else{container.insert(val);for(const auto&it: container){std::cout << it << ", ";}std::cout << "Other container number added.\n";}
}int main(){std::vector<int> vec{1,2,3};expandContainer(vec,100);     // 1, 2, 3, 100, vector number added.//std::deque<int> deq{4,5,6};//expandContainer(deq, 200);    // 200, 4, 5, 6, deque number added.std::set<int> aset{7,8,9};expandContainer(aset, 300);   // 7, 8, 9, 300, Other container number added.
}

此时编译会有如下报错:
在这里插入图片描述
走哪个分支如果在编译时无法确定那么就要保障运行时所有的分支都可以走,很显然else if的分支中有push_front操作,但std::set不支持,所以编译会报错。
因此,如果传入的参数只能走特定的分支,只能在编译时就限制住走的路径,即使用if constexprelse if constexpr

这篇关于constexpr与std::is_same_v碰撞会产生什么火花?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

轻松解决 linux平台 下编辑文档产生的 ^M 符号问题

一、^M:产生的原因:          windows平台下 使用“回车键”,则会在 行尾 产生 ^M 二、产生的后果:        在执行脚本时,shell解析器 会执行错误,弹出类似于:./XXXXX.sh: /bin/sh^M:bad interpreter:No such file or directory         ------解析器会将 末尾 带 ^M 的字段视为 文

芯片后端之 PT 使用 report_timing 产生报告如何阅读

今天,就PT常用的命令,做一个介绍,希望对大家以后的工作,起到帮助作用。 在PrimeTime中,使用report_timing -delay max命令生成此报告。switch -delay max表示定时报告用于设置(这是默认值)。 首先,我们整体看一下通过report_timing 运行之后,报告产生的整体样式。 pt_shell> report_timing -from start_

UE5 中的碰撞问题

文章目录 一、初始准备二、重叠和碰撞三、自定义碰撞 一、初始准备 首先我们创建一个 BP_ThirdPerson 项目,然后在项目中创建两个 Actor 的蓝图 Blueprint 首先是一个移动的 BP_Push,这里使用 time line 循环旋转 cube 的相对位置 得到效果如下 然后是一个旋转的 BP_Rotation,这里同样使用了

「Debug R」报错unable to find an inherited method for function是如何产生的

在一个群里看到这样一条报错,截图如下: 报错信息 当然这种问题解决起来也很快,无非就是把报错信息复制出来放在搜索引擎上,只不过你要挑选合适的搜索引擎。 百度 谷歌 必应 解决方案就是用dplyr::select。 虽然报错解决了,但是我还想着要重复出这个报错。因为只有能重复出报错,才能证明你不是运气好才解

浅析std::ref

目录 1 为什么需要std::ref 2 std::ref使用示例 2.1 std::thread调用 2.1.1 不使用std::ref,编译失败 2.1.2 使用std::ref修饰输入变量 2.2 stl库调用(以for_each 为例) 2.3 std::bind 2.3.1 使用std::ref 2.3.2 使用placeholders::_x同样可以达到同样效果 3

利用定时器1产生全双工软件串口

代码; /*《AVR专题精选》随书例程3.通信接口使用技巧项目:使用AVR定时器1和外中断实现全双工软件串口文件:softuart.c说明:软件串口驱动文件作者:邵子扬时间:2012年12月16日*/#include "softuart.h"// 内部变量struct TSOFTUART stUART;// 软件串口初始化void sfUART_init(void){// 设置IO状态P

使用普通定时器产生半双工软件串口

代码: /*《AVR专题精选》随书例程3.通信接口使用技巧项目:使用普通定时器和外中断实现半双工软件串口文件:softuart.c说明:软件串口驱动文件作者:邵子扬时间:2012年12月16日*/#include "softuart.h"// 声明软件串口变量volatile struct TSOFTUART stUART;// 初始化软件串口void sfUART_init(void)

C++ std::vector 的 emplace_back 能否完全取代 push_back

区别: push_back:先在调用处构造一次 class,传递进 push_back 内后再进行拷贝到缓冲区。 emplace_back:在内部直接将构造 class 的参数转发构造到缓冲区。   如果以上说法不好理解,那么用代码来表示。 // 该 Class 支持隐式构造class Class{public:Class(int a) : _a(a) {}int _a;};ve

std :: this_thread

this_thread 包装了一组可以访问当前线程信息的函数 functions 1、get_id()      获取当前线程的id。 // thread::get_id / this_thread::get_id#include <iostream> // std::cout#include <thread> // std::thread, std