1

阅读一些 C++ 代码时,我遇到了我称之为函数宏的“函数式”使用,大致如下(这是一个完全程式化的例子来说明这一点):

#define TOP_LEVEL(ARG1)     \
ARG1("foo1","bar1")     \
ARG1("foo2","bar2")

#define NEXT_LEVEL(ARG2A, ARG2B)    \
cout << ARG2A << " and " << ARG2B;

TOP_LEVEL(NEXT_LEVEL)

我对这门语言比较陌生,起初我无法弄清楚这一点,但后来我只通过预处理器 ( g++ -E) 运行它,你瞧,它解析为:

cout << "foo1" << " and " << "bar1"; cout << "foo2" << " and " << "bar2";

你看到它在那里做了什么吗?它将宏 NEXT_LEVEL像函数指针一样传递给宏 TOP_LEVEL。看到这可能有多么有用,我想了解更多关于它的信息:将函数传递给其他函数是非常复杂的东西,至少必须对这项技术多说些什么。

然而,尽管进行了大量的谷歌搜索,但我找不到任何证据证明预处理器的这个功能甚至存在,更不用说任何接近文档的东西了: herehereherehere只是跳过这个的宏教程的四个示例;最后一个甚至有一个名为“高级宏技巧”的部分 - 这肯定符合条件!?

(请注意,这与简单地以另一个评估的函数宏作为参数调用函数宏完全不同- FOO(BAR(2)) 更直接。)

我的问题是:

  • 这种行为有实际名称吗?
  • 它在任何地方都有记录吗?
  • 它是常用的,还是有众所周知的陷阱等?
4

2 回答 2

4

这个想法被创造了“X-Macro”。一些定义不包括您的特定示例(X-宏通常涉及更多,包括一个文件),但任何相关信息。搜索时,这将属于该术语。

正如评论中提到的克里斯,Boost.Preprocessor 使用这个想法取得了很好的效果。流行的用途是:BOOST_PP_REPEATBOOST_PP_LIST_FOR_EACH,最强大的:BOOST_PP_ITERATE

BOOST_PP_ITERATE是一个“真正的”X 宏;包含单个文件会扩展为依赖于之前定义的宏的内容。我在另一个答案中展示了一个更“正确”的骨架框架,但一个例子是:

// in xyz_data.def
DEFINE_XYZ(foo, 1, "Description A")
DEFINE_XYZ(bar, 5, "Description B")
DEFINE_XYZ(baz, 7, "Description C")

然后,当我只想要第 1 列时,我可以这样做:

#define DEFINE_XYZ(name, number, desc) some_func(name)
#include "xyz_data.def"

在其他我想为每个函数生成一些函数的地方,我可以这样做:

#define DEFINE_XYZ(name, number, desc)                              \
    int BOOST_PP_CAT(get_number_for_, name)()                       \
    {                                                               \
       std::clog << "Getting number, which is: " desc << std::endl; \
                                                                    \
       return number;                                               \
    }

#include "xyz_data.def"

然后,您可以生成一个名称等于数字等的枚举。

强大之处在于,当我想添加一个新的 xyz 时,我只需将它添加到一个位置,它就会神奇地出现在它需要的任何地方。我在一个非常大的代码库中做了类似的事情,以将一些书签数据保存在一个中心位置,但各种属性在不同位置的使用方式不同。

请注意,通常没有办法解决这个问题。我所拥有的在语法上有所不同,因此没有其他语言功能可以将它推广到那个级别,只有宏。宏并不邪恶。

你所拥有的实际上是一个 X 宏,其中 .def 文件是自包含的,足以成为#define. 换句话说,#include "xyz_data.def"就是TOP_LEVEL.

这样做只有一个很大的缺点,具有讽刺意味的是,这不是 X 宏本身的使用,而是它们对 C 和 C++ 编译器的影响。问题是预处理器允许我们在每次包含文件时更改文件的预处理结果,即使文件内容完全相同

您可能听说过,与现代语言相比,C 和 C++ 的编译速度很慢,这就是原因之一。它没有适当的模块/打包系统,只是临时包含其他文件。而我们刚刚了解到,一般来说这是无法避免的。哎呀。(也就是说,编译器很聪明,例如,当您在文件周围包含保护时会注意到,并避免多次处理它。但这是情景。)

也就是说,使用 X-Macros 本身不应该对实际程序的编译时间产生巨大影响。只是它们的潜在存在延伸到了真实的词中,并与编译器的头脑一致。

于 2013-10-30T03:31:13.413 回答
1

这里有几堂课:C是纯函数式的,

我建议你看看libppmacrofun

于 2015-05-21T18:05:50.463 回答