宏的逆柯里化?

2023-11-29

假设我们有一个#define FOO(x,y) something.

我想构建这样的宏#define BAR that BAR(x)(y)会打电话FOO(x,y)。如果可能的话,我该怎么做?


我尝试了以下操作:

#define BAR(x) FOO(x, BAR_
#define BAR_(y) y)

But got:

error: unterminated argument list invoking macro "FOO"

这是一个 MCVE:

#include <iostream>

#define FOO(x,y) std::cout << x << y << '\n';

#define BAR(x) FOO(x, BAR0
#define BAR0(y) y)

#define STR(...) STR0(__VA_ARGS__)
#define STR0(...) #__VA_ARGS__

int main()
{
    std::cout << STR( BAR(1)(2) );
}


另一种尝试:

#define BAR FOO BAR0
#define BAR0(x) (x, BAR1
#define BAR1(y) y)

这个可以编译,但是会留下FOO (1, 2)最终没有展开。

MCVE:

#include <iostream>

#define FOO(x,y) std::cout << x << y << '\n';

#define BAR FOO BAR0
#define BAR0(x) (x, BAR1
#define BAR1(y) y)

#define STR(...) STR0(__VA_ARGS__)
#define STR0(...) #__VA_ARGS__

int main()
{
    // Prints `FOO (1, 2)`, but I want `std::cout << 1 << 2 << '\n';`
    std::cout << STR( BAR(1)(2) );
}

1. 剖析错误

让我们从这里开始:

#define BAR(x) FOO(x, BAR_
#define BAR_(y) y)
#define FOO(x,y) foo{x|y}
BAR(1)(2)

请注意,我只会使用预处理器来调试预处理器(当我可以简单地调用预处理器时,为什么我需要构建调用预处理器的 C++ 程序?(这是修辞性的 o/c;我是只是在这里讲一个故事))。

CPP 是这样看待这个问题的。我们看BAR;这是一个类似函数的宏。有趣,但除非我们看到左括号,否则不可操作。接下来,我们看到...一个左括号。现在我们已经取得进展了……我们需要确定它的论点。所以我们继续扫描:BAR(1)...那里...那是匹配的左括号...看起来我们正在用一个参数调用。BAR事实证明它是用一个参数定义的,所以这很有效。

现在我们表演参数替换...所以我们注意到BAR的替换列表提到了它的参数(x)以非字符串化、非粘贴的方式。这意味着我们应该评估相应的参数(1),这很容易......这就是它本身。然后,该评估结果将替换替换列表中的参数,因此我们有FOO(1, BAR_。现在我们已经完成了参数替换。

接下来我们需要做的是重新扫描并进一步更换。所以我们重新扫描...FOO, 是啊。这是一个类似函数的宏...FOO(...并且它正在被调用。现在我们已经取得进展了……我们需要确定它的论点。所以,我们继续扫描:FOO(1, BAR_(2)...然后,突然我们到达了文件的末尾。啊?那是不对的。FOO正在被调用;它应该有一个匹配的括号。

你可能天真地认为BAR_(2)应该被调用,但这不是宏的工作方式。他们评估外在和“内”(又名,参数标记)only评估替换列表中是否提及该参数,其中所述提及不是字符串化或粘贴。

请注意,如果FOO如果不是一个类似函数的宏,这个故事将会走向完全不同的方向。在这种情况下,FOO(只是预处理器不关心的标记......所以当它看到时BAR_(2), it will调用宏。但还有另一个“骗局”:如果FOO被忽略而没有实际调用宏FOO,代币将also被跳过。在这两种情况下,FOO(1, 2)最终会被生产出来,这就是你想要的。但如果你随后想要evaluate FOO作为一个类似函数的宏,你只有一个选择。你需要第二次通过;第一遍实际上允许调用序列中的第二个参数来构建宏,并且此遍must not allow FOO被调用。这second需要 pass 才能调用它。

2. 如何做到这一点

嗯,这很简单:

#define DELAY()
#define BAR(x) FOO DELAY() (x, BAR_
#define BAR_(y) y)
#define FOO(x,y) foo{x|y}
#define EVAL(...) __VA_ARGS__
BAR(1)(2)
EVAL(BAR(1)(2))

这是不同之处(第一行)。后BAR的参数替换,它的替换列表现在是FOO DELAY() (1, BAR_而不仅仅是FOO(1, BAR_。现在,在重新扫描期间,它仍然看到FOO,这仍然很有趣......但它看到的下一个标记是DELAY,不是左括号。所以 CPP 在这一次的决定中not调用FOO并传承下去。满后DELAY()膨胀,不会产生任何东西,然后它只会看到(1, BAR_;前三个只是令牌。BAR_然而,是一个宏调用,故事也是如此......所以扩展的结果BAR(1)(2)是生产代币FOO(1, 2),无错误。但这并不能评价FOO.

The EVAL,但是,接受BAR(1)(2)作为一个论点。它的替换列表提到了它的“参数”(不同的 arg 变体),所以BAR(1)(2)被充分评估,产生FOO(1, 2). Then FOO(1, 2)被重新扫描,此时FOO实际上被调用。

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

宏的逆柯里化? 的相关文章

随机推荐

  • 如何将 PDF 文件中的特定 RGB 颜色更改为特定 CMYK 颜色?

    如果我有一个 PDF 文件 其中包含特定 RGB 颜色的对象 文本 艺术线条 并且我想将这些对象转换为具有特定的 CMYK 颜色 有哪些可用的库可以让我做到这一点 请注意 我不需要从任意 RGB 值 映射 到 合适的 CMYK 值的能力 这
  • Scanf_s 警告?跳过用户输入(主题:Runge-Kutta、流行病模拟)

    这是我的第一篇文章 我不得不承认 我在编程方面很糟糕 我是班上那个拼命工作的人 但似乎永远无法像我的其他同学那样掌握编程 所以请保持友善 我将在下面尝试解释我的问题 我有以下代码 已删除注释 但是当我运行它时 我收到类似于下面列出的警告 另
  • 61 秒不活动后,Indy 错误 10038“非套接字上的套接字操作”

    我想从 FTP 服务器下载一些大文件 GB 第一个文件的下载始终有效 然后 当尝试获取第二个文件时 我得到 套接字错误 10038 非套接字上的套接字操作 错误出现在 获取 上 在 获取 之后 我看到这些消息 通过 FTP 状态事件 Sta
  • 是否有一个内置函数可以打印对象的所有当前属性和值?

    所以我在这里寻找的是类似 PHP 的东西print r功能 这样我就可以通过查看相关对象的状态来调试我的脚本 你要vars 夹杂pprint from pprint import pprint pprint vars your object
  • WiX可配置目录的含义是什么?

    我有一个测试安装程序 有 2 个功能 A 和 B A 有 2 个文件 a1 和 a2 B 还有 2 个文件 b1 和 b2 每个文件属于单个组件 Feature A a1 a2 Feature B b1 b2 每个文件的安装位置如下 有些混
  • 从 SqlDataReader 转换为 JSON

    public string toJSON SqlDataReader o StringBuilder s new StringBuilder s Append if o HasRows while o Read s Append Id o
  • PHP CURL 和 SSL 证书(或证书链)

    再会 我有 REST API 可以通过 SSL https 访问 我想将正确的证书 或证书链 与我编写的 PHP 和 CURL 脚本一起发出请求 以下是我的目标的证书方式 http api vkontakte ru 在 Firefox 中看
  • [Shiny]:在另一个tabPanel中添加到另一个tabPanel的链接

    我试图在我的 主页 选项卡面板上放置一个链接到我的应用程序的所有其他选项卡面板 想法如下 ui navbarPage tabPanel home fluidPage fluidRow box this 1st box should lead
  • 将 Oracle SQL Select 转换为 PostgreSQL select

    我有这样的SQL语句 SELECT ABX ABX APO NUMBER COUNT A1 PROCESS MODE AS NUM PLANNING COUNT A2 PROCESS MODE AS NUM SETUP COUNT A3 P
  • cmake 链接错误

    我试图理解为什么在编译使用 CMake 生成的项目时出现链接错误 CMakeFiles txt 为项目的每个文件夹构建一个静态库 然后通过以下方式将所有它们链接在一起 root CMakeLists txt add subdirectory
  • 如何在 ASP.NET MVC 中读取 PPT 文件?

    我的桌面上有一个名为 slide ppt 的 PPT 文件 我想在我的文件夹中阅读该 PPT 文件的所有幻灯片ReadSlide功能如下 public void ReadSlide 如何使用 C 代码读取 PPT 文件中的所有幻灯片 使用如
  • 如何以编程方式在 MoinMoin 中创建新页面?

    我想编写一个 python 脚本来调用一些外部 REST 服务 然后根据我拉回的数据创建 MoinMoin 页面 我在 wiki 农场配置中的 CentOS 5 3 和 MoinMoin 1 9 3 上使用 Python 2 4 3 请注意
  • 如何通过 TextBlock 文本值设置 TextBlock 的 Foreground 属性?

    可以通过 TextBlock 文本值设置 TextBlock 的前景属性吗 例如 文本值为Mike 前景属性为Black 值为Tim 属性值为green等 我用google搜索 但没有找到任何解决方案 如果您希望灵活地做一些聪明的事情 例如
  • 为什么 Rails UJS ajax:success bind 被调用两次?

    我有一个简单的表格 form for posts path id gt new post remote gt true do text field tag post input submit tag Post 我已将回调绑定到ajax su
  • rundll32 url.dll,FileProtocolHandler

    我在用着rundll32 url dll FileProtocolHandler my file dotx在 Windows 下打开文件 它适用于 docx 文档 但当我尝试使用 dotx 文档 模板文档 时 它会根据模板创建一个新的 do
  • 如何使用react-google-maps包通过放大反应来聚焦于标记位置

    如何通过缩放对焦到标记位置 一旦标记位置更改为不同位置 我需要手动放大和缩小并转到市场位置 从字面上看 我需要手动滚动并放大到标记的位置 这很困难 我在用https github com tomchentw react google map
  • 查找数组中的最大值

    将一千 1000 个元素输入到数组中 无内存限制 众所周知 在输入元素时 每当我们输入一个值时 我们都可以通过检查来更新输入值的最大值 但想象一下 如果最大值的位置在 900 左右 如果我从位置 800 到 1000 删除 200 个元素
  • 在什么情况下需要关闭 HTTP 连接?

    在什么情况下需要关闭 HTTP 连接 HTTP 不是一种具有 连接 的协议类型 它是一种具有 连接 的协议 这就是他们所说的 无状态 这意味着每个请求都与其他请求分开 这就是为什么我们有会话 cookie 之类的东西 人们必须设法允许信息在
  • Android 翻转图像动画

    我想通过翻译动画在android中翻转图像 例如 假设我有一张卡 当翻译动画开始时 它会将卡片显示到新位置 现在这里的卡应该翻转吗 从背面到正面 我怎样才能做到这一点 APIdemos 中的示例名称是 旋转3d动画 java 也只需检查下面
  • 宏的逆柯里化?

    假设我们有一个 define FOO x y something 我想构建这样的宏 define BAR that BAR x y 会打电话FOO x y 如果可能的话 我该怎么做 我尝试了以下操作 define BAR x FOO x B