The best way to do this is given in @Bathsheba's answer here: https://stackoverflow.com/a/24551912/1366431
typedef char LINE_AFTER_INCLUDES[__LINE__];
You can then access the value of __LINE__
at that declaration by calling sizeof(LINE_AFTER_INCLUDES)
, because its value has been fixed into part of the newly-declared array type. sizeof
is a C-level compile-time constant, which works for switch
and related things (no division is necessary: the size of char
is guaranteed to be 1, as it's the unit of measurement). The only disadvantage of this is that it's C-level rather than preprocessor-level, so it can't be used with #if
or for token-pasting.
(original, which I spent ages typing:)
So the problem here is that macro definitions are lazy; i.e. that macro invocations aren't expanded until they're actually needed to be inserted into some kind of output. Because of this, __LINE__
's expansion is delayed until it's too late.
Luckily, there's a way to force eager evaluation in the preprocessor - the macro only needs to be demanded by some kind of output - not necessarily program body text. Remember that macros can also be expanded to form the arguments to preprocessor directives - and that preprocessor directives are then - having been controlled by the forced expansion - able to create further definitions. This handy observation is the basis of Boost's "evaluated slots" functionality, which uses it to provide things like eager evaluation and mutable preprocessor variable slots.
Unfortunately you can't use Boost slots with __LINE__
, as it suffers from the same problem - but we can steal the idea to produce two rather inelegant solutions. They're each ugly in their own special ways.
Option 1:
Use a shell script to produce a large number (a few hundred?) of include
-able files with the following naming scheme and contents:
// linedefs/_42_.h
#define LINE_AFTER_INCLUDES 42
...then use as follows:
#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;
}
In other words, use the #include
directive to force expansion of a macro which converts __LINE__
into a filename; including that filename produces the right value for the constant. This is inelegant because it requires a load of extra files and an external tool to generate them, but it's very simple.
Option 2:
Insert a large and ugly block into your main file below the #include
section:
#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() ...
This version uses the #if
directive to force expansion of the __LINE__
macro and convert it into bitflags, which are then recombined at the end. This is highly inelegant because it relies on precomputing the distance between each #if
and the top of the block, since __LINE__
evaluates to different values in the course of the block; and it can't be factored out and hidden in a separate file, or else __LINE__
wouldn't work. Still, it works, and it doesn't require an external tool.
(In the event you have a huge number of #include
lines, extending it to more than 6 bits should be straightforward.)
On the other hand, this sounds like an X/Y problem to me. There has to be an alternative to __LINE__
that would work better for this. If you're counting the number of #include
d files, perhaps you could use something like a line incrementing Boost.Counter at the end of each one? That way, you also wouldn't be vulnerable to formatting changes (e.g. blank lines in the #include
section).