Using #define to include another file in C++/C
Asked Answered
G

4

20

I want to define a macro which includes another header file like so:

#define MY_MACRO (text) #include "__FILE__##_inline.inl"

So that when the preprocessor parses file person.h, MY_MACRO(blahblah) expands to

#include "person.h.inline.inl"

any hints on how to do this ?

Ground answered 5/7, 2010 at 11:2 Comment(0)
G
16

It's not possible to use #define to construct other preprocessor directives, unless you run the preprocessor twice.

But in your case even running the preprocessor twice won't help because the #include must be a single string of the form "..." or <...>.

Gatekeeper answered 5/7, 2010 at 11:4 Comment(3)
This is false, I've worked with code that did this. They included the file multiple times, each time redefining the macro before including it. This caused the macros to be run multiple times, once per include. The use case I saw was pure C code using this trick to make pseudo-templates.Hottempered
@GabeSechan What you described is commonly called X Macro. But it doesn't run the preprocessor multiple times. It redefines macros and includes files multiple times. It's a realy cool trick for some use cases.Touraine
@GabeSechan How to do this? Can I use this way to wrap following code to single macro. constexpr int A = BOOST_PP_COUNTER; #include BOOST_PP_UPDATE_COUNTER()Zygophyte
H
10

You cannot use __FILE__ because that is already quoted, and #include doesn't support string concatenation. But you can use macros after #include:

#define STRINGIZE_AUX(a) #a
#define STRINGIZE(a) STRINGIZE_AUX(a)
#define CAT_AUX(a, b) a##b
#define CAT(a, b) CAT_AUX(a, b)
#define MY_MACRO(file, name) STRINGIZE(CAT(file, CAT(name, _inline.inl)))
#include MY_MACRO(aaaa, qqq)

You should use the equivalent Boost.Preprocessor macros instead of CAT and STRINGIZE to prevent global namespace pollution.

Hortative answered 5/7, 2010 at 11:50 Comment(2)
yes it does manage to include the file, but still i have to use a separate #include, and also it seems FILE is expanded to a quoted string so may be this is not possible at all.Ground
Yes, it's truly impossible. Try to redesign your application so that it's not necessary.Hortative
J
3

You can't write other pre-processor directives using the pre-processor. However, I believe you could define just the file name:

#define MY_MACRO(name) "__FILE__##name_inline.inl"

#include MY_MACRO(name)

The pre-processor runs multiple times until there are no further substitutions it can make, so it should expand the name first and then #include the referenced file.

EDIT: I just tried it and the pre-processor can't handle the quotes like that.

#define MY_MACRO(x) <__FILE__##x_inline.inl>
#include MY_MACRO(foo)

works OK, but <> may not be what you wanted.

EDIT2: As pointed out by sth in comments, the __FILE__ does not expand correctly, which makes this probably not what you want after all. Sorry.

Jolee answered 5/7, 2010 at 11:20 Comment(5)
codepad.org/AxNh2h3F Apparently "__FILE__##name_inline.inl" is treated literally, but if you switch it to #define MY_MACRO(name) <__FILE__ ## name ## _inline.inl> then you can actually include a file variably.Thigmotropism
I don't think this works at all. The macro you provide expands to <__FILE__x_inline.inl>, while it should be something like <person.h_foo_inline.inl>.Bohman
@sth: You're quite right, I missed that. I tried breaking it down to two stages as well: [code]#define MY_MACRO(a) FILE ##a #define MY_MACRO_2(b) < MY_MACRO(b) _inline.inl > #include MY_MACRO_2(test)[/code] but that doesn't help either.Jolee
All this cannot work because __FILE__ expands to a quoted literal string. The concatenation of __FILE__ with something else then has the quotes at the wrong place.Hortative
If the file name "person.h".inline.inl is also acceptable, then your solution works, but it's a bit nonportable because file names containing quotes are not allowed on Windows. However, it looks a bit ugly to require such file names only to save a few keystrokes.Hortative
I
-6
#if 0 /*Windows*/
#define MKDIR_ENABLER <direct.h>
#define MY_MKDIR(x,y) _mkdir((x))
#else /*Linux*/
#define MKDIR_ENABLER <sys/stat.h>
#define MY_MKDIR(x,y) mkdir((x),(y))
#endif

#include MKDIR_ENABLER

int main(void)
{
    MY_MKDIR("more_bla",0644);
    return 0;
}

This code includes the appropriate header file for mkdir (because it's different on UNIX and Windows) and introduces a nice wrapper for it.

Ike answered 27/1, 2015 at 9:32 Comment(1)
And in what way this is providing an answer?Millhon

© 2022 - 2024 — McMap. All rights reserved.