首页 > 编程语言 >分支代码元编程示例

分支代码元编程示例

时间:2023-07-01 19:58:18浏览次数:55  
标签:struct 示例 int 代码 编程 constexpr template Imp type

分支代码的元编程

最简单的编译期执行的分支语句

直接使用constexpr:

#include<iostream>
#include<type_traits>
constexpr int fun(int x)
{
    if(x > 3)
      return x * 2;
    else
      return x - 100;
}
constexpr int x = fun(100);

但是,这种方法的应用非常有限,生成的也是编译期常量。

基于if constexpr 的分支

便于理解且只能处理数值,同时要小心引入运行期计算。例如下面运用数值模板的例子。


template<int x>
int func()
{
 if constexpr (x > 3)
   return x * 2;
  else
   retrun x - 100;
}
int y = func<100>();

值得注意的是,这里的func()函数不是在编译期而是在运行期执行的。但由于这是数值模板,所以参数必须在编译期获得。同时分支语句也会在编译期处理。

之所以要小心在运行期运算,是因为有时候会忘记写if constexpr,这样就会将编译期的分支退化为运行期的计算。

基于(偏)特化引入分支

这是一种常见的元编程方式但书写较为麻烦。比如:


#include<type_traits>
template  <int x>
struct Imp
{
  constexpr static int value = x * 2;
};

template<>
struct Imp<100>
{
   constexpr static int value = 100 - 3;
};
constexpr int x = Imp<100>::value;

这种偏特化的方式不仅可以处理数值,还可以处理类型和模板。比如下面的例子就是利用偏特化返回不同的类型:

#include<type_traits>
template  <int x>
struct Imp
{
   constexpr static int value = x * 2;
   using type = int;
};

template<>
struct Imp<100>
{
   constexpr static int value = 100 - 3;
   using type = double;
};
using type_ = Imp<100>::type;

而在C++20中,我们还可以利用concept引入对模板的类型限制来实现分支语句。

template<int x>
struct Imp;

template<int x>
  requires (x < 100)
struct Imp<x>
{
  constexpr static int value = x * 2;
  using type = int;
};

template<int x>
  requires (x >= 100)
struct Imp<x>
{
   constexpr static int value = 100 - 3;
   using type = double;
};

constexpr int x = Imp<97>::value;  
std::cout << x << "\n";

输出为:

194

利用std::conditional引入分支

template< bool B, class T, class F >
struct conditional;

提供成员 typedef type ,若 B 在编译时为 true 则定义为 T ,或若 B 为 false 则定义为 F 。添加 conditional 的特化的程序行为未定义。

#include<iostream>
#include<type_traits>
#include<typeinfo>
typedef std::conditional<true, int,double>::type Type1;
typedef std::conditional<false, int, double>::type Type2;
typedef std::conditional<sizeof(int) >= sizeof(double), int, double>::type Type3;

std::cout << typeid(Type1).name() << '\n';
std::cout << typeid(Type2).name() << '\n';
std::cout << typeid(Type3).name() << '\n';

输出为:

int  
double    
double

std::conditional语法简单但应用场景受限(只能返回类型,类似于运行期的三元表达式)。

经典的利用SFINAE(Substitution failure is not an error,替换失败并非错误)引入分支

什么是SFINAE

基于std::enable_if引入分支

语法不易懂但功能强大
可能的实现:

template<bool B, class T = void>
struct enable_if {};
 
template<class T>
struct enable_if<true, T> { typedef T type; };

如果B为true的时候,才可以得到一个type,例如 template< bool B, class T = void > using enable_if_t = typename enable_if<B,T>::type;而如果为false,以上代码自然就无效了。于是就出现了所谓的匹配失败(SFINAE)

而std::enable_if_t基于模板的 SFINAE 和 匿名类型参数 的基础概念上进行了简洁且完美的封装。
enable_if_t 强制使用 enable_if 的 ::type 来触发 SFINAE 规则, 如果失败则跳过当前匹配进入下一个匹配。

template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;

先看一种在函数模板中的应用:

#include<iostream>
#include<type_traits>
#include<typeinfo>
template<int x, std::enable_if_t<(x<100)>* = nullptr>
constexpr auto fun()
{
 return x * 2;
}

template<int x, std::enable_if_t<(x >= 100)>* = nullptr>
constexpr auto fun()
{
  return x - 3;
}
constexpr auto x = fun<97>();
std::cout << x << "\n";

输出为:

194

还可以在类模板中使用:

 
template<int x, typename = void*>
struct Imp;

template<int x>
struct Imp<x, std::enable_if_t<(x < 100)>*>
{
	constexpr static int value = x * 2;
	using type = int;
};

template<int x>
struct Imp<x, std::enable_if_t<(x >= 100)>*>
{
	constexpr static int value = x - 3;
	using type = double;
};

constexpr auto x = Imp<101>::value;
std::cout << x << "\n";

输出为:

98

注意用缺省模板实参不能引入分支! 否则会被看做重定义。

C++17:基于std::void_t的分支

template< class... >
using void_t = void;

这是一个可变长度的别名模板。

基于三元运算符的分支

template<int x>
constexpr auto fun = (x < 100) ? x * 2 : x - 3;

constexpr auto x = fun<102>;
std::cout << x << "\n";

输出为:

99

标签:struct,示例,int,代码,编程,constexpr,template,Imp,type
From: https://www.cnblogs.com/wyfc4/p/17519825.html

相关文章

  • [MAUI]用纯C#代码写两个漂亮的时钟
    @目录时钟1绘制锯齿表盘绘制指针绘制沿路径文本时钟2绘制表盘绘制指针项目地址谷歌在2021年5月份推出的Android12给我们带来了新的UI设计规范MaterialYou,你是否已经体验到了MaterialYou设计的魅力了呢?在原生主屏幕启动器中,有一个时钟小部件。这个小部件可以选择表盘风格。......
  • ruby网络编程(1)
    目录socket概述ftpclientsocket概述类套接字socket提供对底层操作系统套接字实现的访问。它可以用来提供比协议特定套接字类更多的操作系统特定功能。在Socket::Constants下定义的常量也在Socket下定义。例如,Socket::AF_INET和Socket:∶Constants::AF_NET都可用。SOC......
  • 并发编程
    并发安全问题是由于多线程环境下对临界区进行写操作而引发的,为了解决这个问题,可以采取保证临界区的原子性的措施,例如加锁或使用CAS操作。加锁机制通过确保同一时间只有一个线程可以进入临界区来保证原子性,而CAS操作是一种无锁的乐观并发控制方式,通过比较并交换操作来实现原子性。......
  • Markdown 使用diff高亮代码区某行数据
    使用diff标明代码区即可如:```difffunmain(){+say("")return""}funmain(){-say("")return""}效果:funmain(){+say("")return""}funmain(){-say("&quo......
  • qt 网络编程
    UDP是一个轻量级、不可靠、面向数据报的、无连接的协议,多用于可靠性要求不严格,不是非常重要的传输。//服务器端  h1=newQUdpSocket(this);h1.bind(5555,QUdpSocket::ShareAddress);//绑定端口号connect(h1,&QUdpSocket::readyRead,this,&xx::YY);//接受到其它地方发......
  • A004 《天狗食月》编程 源码
    一、课程介绍本节课将学习Python中的for循环,并应用画笔后退和画圆的知识,最终绘制出月食过程。二、重难点解析for循环我们在编程时,有些代码和逻辑是重复的,这个时候可以考虑使用for循环,减少重复的代码。for循环的基本格式与缩进基本格式:foriinrange(3):语句1语句2......
  • 使用 ABAP 代码查找系统可用的 user exit
    ABAPUserExit是SAP系统中一种提供给客户扩展和修改标准程序的技术手段,这种机制允许客户在不修改SAP源代码的前提下,实现对标准程序的定制和功能增强。ABAP(AdvancedBusinessApplicationProgramming)是SAP的一种编程语言,用于开发企业级应用程序。在SAP系统中,有许多预先......
  • 快速使用Python-Tkinter设计界面 方法与代码
    作者:干饭小熊猫链接:https://www.zhihu.com/question/68663671/answer/2519875621来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 1简介1.1Tkinter是什么?Tkinter是Python自带的GUI库,Python的IDEL就是Tkinter的应用实例。Tkinter可以看作是Tk......
  • 参考资料------ 快速使用Python-Tkinter设计界面 方法与代码-20230701
    作者:干饭小熊猫链接:https://www.zhihu.com/question/68663671/answer/2519875621来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 1简介1.1Tkinter是什么?Tkinter是Python自带的GUI库,Python的IDEL就是Tkinter的应用实例。Tkinter可以看作是Tk......
  • SAP 电商云 footer 区域 Link Component HTML 源代码的详细讲解
    如下图所示:这个linkComponent生成的a元素的HTML代码:<ahref="http://www.twitter.com/SAP_CX"target="_blank"rel="noopener">Twitter-j<!--bindings={"ng-reflect-ng-template-outlet":"[objectObject]"}......