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函数和宏(下) 的相关文章

  • Volatile.Read 和 Volatile.Write 背后的逻辑是什么?

    来自 MSDN Volatile Read 读取字段的值 在需要它的系统上 插入一个 阻止处理器重新排序内存的内存屏障 操作如下 如果在该方法之后出现读或写 代码 处理器无法移动它before这个方法 and Volatile Write
  • 我应该把 try/catch 和“using”语句放在哪里? [复制]

    这个问题在这里已经有答案了 可能的重复 try catch using 正确的语法 https stackoverflow com questions 4590490 try catch using right syntax 我想try c
  • 元组在 VS2012 中如何工作?

    Visual Studio 2012 功能 tuples但不是可变参数模板 这是如何完成的 如何在不使用可变模板的情况下实现元组 简而言之 微软做了与之前在 NET 中实现类似元组的数据类型完全相同的事情 创建许多版本 每个版本都有固定数量
  • 是否可以从 C++ 应用程序调用 C# 应用程序?

    我是一名编程学生 现在我已经上了两门 C 课程 这个学期我将参加我的第一门 C 课程 出于好奇 是否可以从 C 应用程序调用 C 应用程序 如果是的话 是否还可以检查运行该程序的计算机是否具有 NET框架 我只是很好奇 我想如果可能的话 这
  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • C free() 是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 malloc 和 free 如何工作 https stackoverflow com questions 1119134 how malloc and free work include
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 异常堆栈跟踪不显示抛出异常的位置

    通常 当我抛出异常 捕获它并打印出堆栈跟踪时 我会看到抛出异常的调用 导致该异常的调用 导致该异常的调用that 依此类推回到整个程序的根 现在它只向我显示异常所在的调用caught 而不是它所在的地方thrown 我不明白是什么改变导致了
  • 在 ASP.NET MVC 中将模型从视图传递到控制器

    我正在 ASP NET MVC 中开发我的第一个应用程序 但遇到了一个我无法解决的问题 即使在阅读了整个互联网之后也是如此 因此 我有几个使用视图模型创建的视图 它们是报告 这些视图模型是根据用户选择标准填充的 我正在尝试构建一种接受模型并
  • C 中“complex”的默认类型

    根据我读过的文档 C99 和更高版本的支持float complex double complex and long double complex作为复杂类型 但是 此代码在使用时编译时不会发出警告gcc Wall Wextra inclu
  • 如何使用 Roslyn 通过扩展方法、静态类中的方法以及带有 ref/out 参数的方法来访问调用

    我正在致力于创建一个开源项目 用于创建 NET UML 序列图 该项目利用名为 js sequence diagrams 的 javascript 库 我不确定 Roslyn 是适合这项工作的工具 但我想我应该尝试一下 所以我整理了一些概念
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 为什么不能调用带有 auto& 参数的 const mutable lambda?

    include
  • 如何使用 CSI.exe 脚本参数

    当你运行csi exe 安装了 Visual Studio 2015 update 2 您将得到以下语法 Microsoft R Visual C Interactive Compiler version 1 2 0 51106 Copyr
  • doxygen c++:记录由“using”声明公开的私有继承成员

    作为一个例子 我有以下课程 class A public void methodOne class B private A public Brief description using A methodOne 我还没有找到强制 doxyge
  • 浮点字节序?

    我正在为实时海上模拟器编写客户端和服务器 并且由于我必须通过套接字发送大量数据 因此我使用二进制数据来最大化可以发送的数据量 我已经了解整数字节顺序以及如何使用htonl and ntohl为了规避字节顺序问题 但我的应用程序与几乎所有模拟
  • 如何在dll级别读取app.config? [复制]

    这个问题在这里已经有答案了 我在一个解决方案中有一个控制台应用程序项目和库项目 dll The 图书馆项目有 app config 文件 我在其中存储我在库中使用的一些键值对 控制台应用程序引用此 dll 我有另一个 app config
  • “必须声明标量变量”错误[重复]

    这个问题在这里已经有答案了 必须声明标量变量 Id SqlConnection con new SqlConnection connectionstring con Open SqlCommand cmd new SqlCommand cm
  • 使用 C# 动态创建按钮并按预定义的顺序放置它们

    NET 4 5 C 创建 Windows 窗体 我想动态创建和添加按钮并为其分配单击事件 但希望它们以特定的方式动态放置 就像图像一样 我的问题是如何以上述方式动态放置按钮 即 4x4 格式 一行 4 个按钮 4 列 但行数不受限制 是否可
  • CLion - 命令行程序参数

    当我分配给 运行 调试配置 程序参数 之类的 aaa bbb 然后打印它时 任何人都可以告诉我 JetBrains CLion 有什么问题吗 printf s n argv 1 我刚刚得到 aaa 而它必须是 aaa bbb 因为它们用双引

随机推荐

  • 使用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函数和宏(下)

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