010.CMake函数和宏(下)

2023-10-26

函数和宏的根本区别

函数和宏之间的一个根本区别,是函数引入了一个新的变量作用域,而宏没有。在函数内定义或修改的变量对函数外同名的变量没有影响,而宏与其调用者共享相同的变量范围。但是请注意,函数不会引入新的策略作用域(cmake_policy)。

如前文所述,CMake函数和宏不支持直接返回值,但有专门的命令实现这一目的。set()命令的PARENT_SCOPE关键字可用于修改调用者作用域中的变量,而不是函数中的局部变量。虽然这与从函数返回值不同,但它确实允许将一个值(或多个值)传递回调用方。

一种常见的方法是调用者给函数传变量名,函数使用上述方法修改之(这个C++传引用有些相似)。如下:

function(func resultVar1 resultVar2)
	set(${resultVar1} "First result" PARENT_SCOPE)
	set(${resultVar2} "Second result" PARENT_SCOPE)
endfunction()
func(myVar otherVar)
message("myVar: ${myVar}")
message("otherVar: ${otherVar}")

另一种方法是让函数自己设置变量,而不是让调用者指定变量名。但这有可能导致变量名的冲突,因为函数的编写者并不能预判使用者会不会也定义了相同的变量名。所以推荐使用前一种方法。

宏的处理方式与函数相同,通过传参指定要设置的变量的名称。唯一的区别是PARENT_SCOPE关键字不应该在宏中使用,因为宏并不会产生一个新的作用域,他本身就已经修改了调用者作用域中的变量。实际上,使用宏而不是函数的一个重要的原因是调用者需要设置许多变量

前文中介绍了return()命令,其可以从文件或函数中提前结束处理。如前所述,return()不返回值,它只返回到父作用域。如果在函数中调用return(),则处理过程会立即返回给调用者,即跳过函数的其余部分。另一方面,在宏中return()的行为则截然不同。由于宏不引入新的作用域,return()导致调用者提前结束,并返回到调用者的调用者作用域。

这一点很要命,稍不注意就可能出意外。

同名覆盖

调用function()或macro()来定义新命令时,如果已存在具有同名的命令,则新命令会覆盖旧命令。

这一点似乎是理所当然的,但如果还想用旧命令的功能,有一个特殊技巧可以办到。即在命令前加一个下划线,如_command。此时_command指的是旧命令的功能。无论旧名称是内置命令还是自定义函数或宏,都适用。

了解此行为的人有时会试图利用此行为来增强旧命令的功能,如下所示:

function(someFunc)
	# Do something...
endfunction()

function(someFunc)
	if(...)
		# 一些其他处理动作
	else()
		# 调用旧命令的功能
		_someFunc()
	endif()
endfunction()

如果命令只被这样重写过一次,则这种方法可以工作,但如果再次被重写,则无法再访问原始命令。也就是说假如有先后定义的N个同名命令,command,则_command单指第N-1个,而不是递归的往前调用,这可能导致严重的麻烦。如下:

function(printme) #1
	message("Hello from first")
endfunction()
function(printme) #2
	message("Hello from second")
	_printme()
endfunction()
function(printme) #3
	message("Hello from third")
	_printme()
endfunction()
printme()

实际上_printme()就是指的第二个,在第二个中调用_printme(),实际上是调用自身。假如有个循环依赖于第一个命令的结果,则可能永远出不了循环,因为第一个命令已经被彻底覆盖,找不回了。

鉴于这种技巧可能导致不必要的麻烦,所以并不推荐使用。覆盖旧命令是可以的,但应该假设新的实现完全取代了旧的实现,旧的实现不会再被使用。

总结

结合前文,函数和宏相关的内容差不多了。很有意思。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

010.CMake函数和宏(下) 的相关文章

随机推荐

  • 使用Python做副业,我需要具备什么技能水平?

    B站主页 https space bilibili com 1707990930 欢迎 点赞 收藏 评论 如有错误请指正 Python Java领域博主 你们的支持是我最大的动力 文章目录 使用Python做副业 我需要具备什么技术水平 爬
  • SpringDoc + Spring Gateway + Knife4j 集成

    前言 如果有必要使用Spring Doc时 好像官方的文档相对较少 为此重新尝试了一把 SpringDoc的基本使用请查看官网 这里关键说下Spring Gateway 的配置 POM xml
  • python生成随机字符串包含数字字母_如何在Python中生成带有大写字母和数字的随机字符串?...

    您可以使用random choice list of choices 获取随机字符 然后循环遍历并获取列表 最后加入该列表以获取字符串 这里的选择列表是大写字母和数字 例如 import string import random def g
  • 2021年自然语言处理与信息检索国际会议(ECNLPIR 2021)EI检索

    2021年自然语言处理与信息检索国际会议 ECNLPIR 2021 重要信息 会议网址 www ecnlpir org 会议时间 2021年8月13 15日 召开地点 瑞典斯德哥尔摩 截稿时间 2021年6月30日 录用通知 投稿后2周内
  • 2021-12-01 xorm.io/builder

    xorm io builder go和xorm的轻量级快速sql构建器 一般用来构造查询条件 用法 初始化一个cond cond builder NewCond cond的方法 cond And builder语句 且连接 可连接多个con
  • 3张照片打造专属形象!酷蛙FaceChain解密个人写真开源项目,人人AIGC!

    一 背景说明 各类AI写真软件由于其精准的个人形象 精美的生成效果引爆了朋友圈传播 证件照满足了用户刚需 古装照等风格照满足了用户 美照 的需求 酷蛙FaceChain开源项目团队推出了开源版本 希望结合开源社区开发者的力量 可以让图片应用
  • 操作符详解

    在之前的篇章说过 我们不能自己创建操作符 只能使用c语言所给的操作符 那今天就来看看操作符具体有哪些呢 目录 1 操作符分类 2 算术操作符 3 移位操作符 左移操作符 右移操作符 4 位操作符 5 赋值操作符 6 单目操作符 7 关系操作
  • 强化学习笔记------第一章----强化学习概述(超详细)

    强化学习讨论的问题是一个智能体 agent 怎么在一个复杂不确定的环境 environment 里面去极大化他能获得的奖励 首先 我们可以把强化学习和监督学习做一个对比 例如图片分类 监督学习 supervised learning 指的是
  • 一篇史上最全面的 Vue 代码风格指南,建议收藏

    作者 卡喵妹 https juejin cn post 6987349513836953607 一 命名规范 市面上常用的命名规范 camelCase 小驼峰式命名法 首字母小写 PascalCase 大驼峰式命名法 首字母大写 kebab
  • 【云原生】SpringCloud-Spring Boot Starter使用测试

    目录 Spring Boot Starter是什么 以前传统的做法 使用 Spring Boot Starter 之后 starter 的理念 starter 的实现 创建Spring Boot Starter步骤 在idea新建一个sta
  • Computer【HDU-2196】【在线LCA+树的直径】

    题目链接 include
  • PHP 自学教程之自定义函数及数组

    一 自定义函数 自定义函数就是我们自己定义的函数 在PHP中自定义函数格式如下 function funname arg1 arg2 arg3 TODO return values 下面举一个按值传递函数
  • Python 制作马赛克拼合图像

    Python 制作马赛克拼合图像 文章目录 Python 制作马赛克拼合图像 知识点 效果 环境 原理 RGB 色彩空间 HSV 色彩空间 RGB 与 HSV 色彩空间的转换 马赛克图片拼合 数据准备 导入需要的库 计算图像平均 HSV 值
  • Linux下Mysql

    1 安装查看是否已经安装了MYSQLrpm qa mysqlmysql 4 1 7 4 RHEL4 1点开add remove programe里面的mysql的detail勾上mysql server2 启动来检测mysql是否已经启动s
  • Redis系列--redis持久化

    一 为什么需要持久化 redis本身运行时数据保存在内存中 如果不进行持久化 那么在redis出现非正常原因宕机或者关闭redis的进程或者关闭计算机后数据肯定被会操作系统从内存中清掉 当然 redis本身默认采用了一种持久化方式 即RDB
  • Matlab 2021b安装教程-Matlab分析软件下载方法

    MATLAB是美国MathWorks公司出品的商业数学软件 用于算法开发 数据可视化 数据分析以及数值计算的高级技术计算语言和交互式环境 主要包括MATLAB和Simulink两大部分 下载方法 https docs qq com shee
  • 【数据分析实战】基于python对酒店预订需求进行分析

    文章目录 引言 数据加载以及基本观察 缺失值观察及处理 缺失值观察以及可视化 缺失值处理 用户数据探索 什么时间预定酒店将会更经济实惠 哪个月份的酒店预订是最繁忙的 商家数据探索 按市场细分的不同预定情况是怎样的 什么样的人更容易取消预订
  • CCNA考试题库中英文翻译版及答案11

    26 Two routers named Atlanta and Brevard are connected by their serial interfaces as shown in the exhibit but there is n
  • SpringCloud-微服务架构编码构建

    SpringCloud Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具 例如配置管理 服务发现 断路器 智能路由 微代理 控制总线 分布式系统的协调导致了样板模式 使用Spring Cloud开发人员可以快速
  • 010.CMake函数和宏(下)

    文章目录 函数和宏的根本区别 同名覆盖 总结 函数和宏的根本区别 函数和宏之间的一个根本区别 是函数引入了一个新的变量作用域 而宏没有 在函数内定义或修改的变量对函数外同名的变量没有影响 而宏与其调用者共享相同的变量范围 但是请注意 函数不