本质上,我想这样做:
#include "foo.h"
#include "bar.h"
static const unsigned line_after_includes = __LINE__;
int main()
{
foo(line_after_includes);
bar(line_after_includes);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
除了这样:
#include "foo.h"
#include "bar.h"
#define LINE_AFTER_INCLUDES __LINE__
int main()
{
FOO(LINE_AFTER_INCLUDES);
BAR(LINE_AFTER_INCLUDES);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是否可以扩展为定义的行上LINE_AFTER_INCLUDES的值,以便稍后我可以将其与其他宏一起使用?我只想使用第一个代码片段中的变量,但我需要该值作为整数文字,因为我将在 switch 语句中使用它。另一种选择是做__LINE__LINE_AFTER_INCLUDES
#define LINE_AFTER_INCLUDES 3 // MAKE SURE THIS IS ON LINE IT'S DEFINED AS!!!
Run Code Online (Sandbox Code Playgroud)
这是丑陋且难以维护的。我会满足于此,但我会做一些比这个例子更复杂的事情......
@Bathsheba 的答案给出了最好的方法: https: //stackoverflow.com/a/24551912/1366431
typedef char LINE_AFTER_INCLUDES[__LINE__];
Run Code Online (Sandbox Code Playgroud)
__LINE__然后,您可以通过调用 来访问该声明处的值sizeof(LINE_AFTER_INCLUDES),因为它的值已被固定到新声明的数组类型的一部分中。sizeof是一个 C 级编译时常量,适用于switch和 相关事物(不需要除法: 的大小char保证为 1,因为它是测量单位)。这样做的唯一缺点是它是 C 级别而不是预处理器级别,因此它不能与标记粘贴一起使用#if或用于标记粘贴。
(原文,我花了很长时间打字:)
所以这里的问题是宏定义是惰性的;即宏调用只有在实际需要插入到某种输出中时才会展开。因此,__LINE__扩张被推迟,直到为时已晚。
幸运的是,有一种方法可以在预处理器中强制进行急切求值 - 宏只需要某种输出的要求 - 不一定是程序正文文本。请记住,宏也可以扩展以形成预处理器指令的参数 - 并且预处理器指令 - 由强制扩展控制 - 能够创建进一步的定义。这种方便的观察是 Boost 的“评估槽”功能的基础,该功能使用它来提供诸如热切评估和可变预处理器变量槽之类的功能。
不幸的是,你不能使用 Boost 插槽__LINE__,因为它也遇到同样的问题 - 但我们可以窃取这个想法来产生两个相当不优雅的解决方案。他们每个人都以自己独特的方式丑陋。
使用 shell 脚本生成大量(几百个?)include具有以下命名方案和内容的 -able 文件:
// linedefs/_42_.h
#define LINE_AFTER_INCLUDES 42
Run Code Online (Sandbox Code Playgroud)
...然后使用如下:
#define GEN_LINE_INC(L) _GEN_LINE_S(_GEN_LINE_(L))
#define _GEN_LINE_(L) linedefs/_##L##_.h
#define _GEN_LINE_S(S) _GEN_LINE_S2(S)
#define _GEN_LINE_S2(S) #S
#include "foo.h"
#include "bar.h"
#include GEN_LINE_INC(__LINE__)
int main()
{
FOO(LINE_AFTER_INCLUDES);
BAR(LINE_AFTER_INCLUDES);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
换句话说,使用该#include指令强制扩展转换__LINE__为文件名的宏;包含该文件名会产生正确的常量值。这是不优雅的,因为它需要加载额外的文件和外部工具来生成它们,但它非常简单。
将一个又大又难看的块插入到主文件的以下#include部分中:
#include "foo.h"
#include "bar.h"
// <- This line is the one we generate the number for
#define LINE_BIT_0 0
#define LINE_BIT_1 0
#define LINE_BIT_2 0
#define LINE_BIT_3 0
#define LINE_BIT_4 0
#define LINE_BIT_5 0
#if (__LINE__ - 7) & 1
# undef LINE_BIT_0
# define LINE_BIT_0 1
#endif
#if (__LINE__ - 11) >> 1 & 1
# undef LINE_BIT_1
# define LINE_BIT_1 (1 << 1)
#endif
#if (__LINE__ - 15) >> 2 & 1
# undef LINE_BIT_2
# define LINE_BIT_2 (1 << 2)
#endif
#if (__LINE__ - 19) >> 3 & 1
# undef LINE_BIT_3
# define LINE_BIT_3 (1 << 3)
#endif
#if (__LINE__ - 23) >> 4 & 1
# undef LINE_BIT_4
# define LINE_BIT_4 (1 << 4)
#endif
#if (__LINE__ - 27) >> 5 & 1
# undef LINE_BIT_5
# define LINE_BIT_5 (1 << 5)
#endif
#define LINE_AFTER_INCLUDES (LINE_BIT_0 | LINE_BIT_1 | LINE_BIT_2 | LINE_BIT_3 | LINE_BIT_4 | LINE_BIT_5)
int main() ...
Run Code Online (Sandbox Code Playgroud)
此版本使用#if指令强制扩展宏__LINE__并将其转换为位标志,然后在最后重新组合。这是非常不#if优雅的,因为它依赖于预先计算每个块与块顶部之间的距离,因为__LINE__在块的过程中评估为不同的值;并且不能将其分解并隐藏在单独的文件中,否则__LINE__将无法工作。尽管如此,它仍然有效,并且不需要外部工具。
(如果您有大量#include行,将其扩展到 6 位以上应该很简单。)
另一方面,这对我来说听起来像是一个 X/Y 问题。必须有一种替代方案__LINE__可以更好地解决这个问题。如果您正在计算 d 文件的数量#include,也许您可以在每个文件的末尾使用一行递增 Boost.Counter 之类的东西?这样,您也不会容易受到格式更改的影响(例如,该#include部分中的空行)。