9

Initially I thought I needed this, but I eventually avoided it. However, my curiosity (and appetite for knowledge, hum) make me ask:

Can a preprocessor macro, for instance in

#include "MyClass.h"

INSTANTIATE_FOO_TEMPLATE_CLASS(MyClass)

expand to another include, like in

#include "MyClass.h"

#include "FooTemplate.h"
template class FooTemplate<MyClass>;

?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
moala
  • 5,094
  • 9
  • 45
  • 66
  • 3
    One day you will want to transfer your code to an OS like Linux where case is significant (i.e. Foo.h and foo.h are two different files) and then all the misspellings that are not caught on Windows will come home to roost. alternatively, if you are a Linux person, you will one day want to go the other way, with different but equally horrible problems. –  Aug 11 '09 at 18:29
  • 1
    I agree with the always-lowercase rule for file names. I wrote that this way because I wanted to exclude the issue of lowercase conversion (class name -> file name). But that is worth to mention, thanks. +1! – moala Aug 11 '09 at 18:37
  • Our rule is that filenames match exactly the naming scheme for our types and functions. We do exactly as the Questioner here, a type name FooType will be defined in FooType.h. As with any "style" guideline, choose a style and stick with it. Having said that we develop heavily on linux and so this rule is automatically enforced for us by the OS....hmmmmm..... – Richard Corden Aug 11 '09 at 22:26
  • Ok. That was an error. I don't like having uppercases in file names, but I like having uppercases in type names. But I should have written both lowercase just for the question. @Richard Corden: Having the filesystem and compiler enforce the rule may be temporary, and any port to other OSs erases completely this security. At least, with a totalitarian lowercase file name rule, risky behaviour and errors are immediately visible, before any problem has occured. Which I prefer. – moala Aug 11 '09 at 23:20
  • 1
    @moala. Thinking about this a bit more, it struck me that no matter what you do (lower case or mixed case matching contents) it will need to be enforced by some external utility. There's always the chance that someone will make a mistake and unless you have OS support (as in my case) then you have to check this via some script/tool. It's easier to check for all lower case - but it's not that difficult to check that the name matches at least one identifier in the file either. < blatent plug > And you may even have a static analysis tool that does the work for you!!! ;) < / blatent plug >. – Richard Corden Aug 12 '09 at 08:35

3 Answers3

14

I believe that cannot be done, this is because the pre-processor is single pass. So it cannot emit other preprocessor directives.

Specifically, from the C99 Standard (6.10.3.4 paragraph 3):

3 The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, ...

Interestingly enough, This is why the unary _Pragma operator was added to c99. Because #pragma could not be emited by macros, but _Pragma can.

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • Well, it can of course emit the directives. what it cannot do is process them in the same preprocessor pass. –  Aug 11 '09 at 18:19
  • 1
    Since the `#` and `##` characters have special meanings in macros, I don't see how you could actually emit a directive... – Evan Teran Aug 11 '09 at 18:21
  • Actually the GCC preprocessor seems to allow "#define X #ifdef X" where the space between the #ifdef and the second X is really a newline, and this actually emits a #ifdef when you run cpp on it. Someone else might like to check this, as I've just had a couple of beers :-) –  Aug 11 '09 at 18:37
  • Yea, it seems that it is possible to create something that "resembles" a directive, but the standard specifically states (see my edit) that such a construct is not processed as a directive. – Evan Teran Aug 11 '09 at 18:41
  • Yes, I wasn't suggesting that the OP could do what he appears to want. –  Aug 11 '09 at 18:53
10

The C standard says this about preprocessing directives (C99 - 6.10(2) - Preprocessing directives):

A preprocessing directive consists of a sequence of preprocessing tokens that begins with a # preprocessing token that (at the start of translation phase 4) ...

and (C99 - 6.10(7)):

The preprocessing tokens within a preprocessing directive are not subject to macro expansion unless otherwise stated.

EXAMPLE In:

#define EMPTY
EMPTY # include <file.h>

the sequence of preprocessing tokens on the second line is not a preprocessing directive, because it does not begin with a # at the start of translation phase 4, even though it will do so after the macro EMPTY has been replaced

So, no, macros cannot expand into a '#include' preprocessing directive. Those directives need to be in place at the start of translation phase 4 (when handling those directives takes place preprocessing happens). Since macro expansion occurs during phase 4, macros can't cause something to exist at the start of phase 4.

I'd like to point out however, that the following does work:

#ifdef WIN32
#define PLATFORM_HEADER "platform/windows/platform.h"
#else
#define PLATFORM_HEADER "platform/linux/platform.h"

#include PLATFORM_HEADER

because the C standard says this (C99, 6.10.2(4) - Source file inclusion):

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text. (Each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens.)

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • i looked at that part of the standard, but I don't think it is the most relevant section. The example is not one that tries to emit a directive. It is instead an example of a directive which is not preceeded by "whitespace" (even though the EMPTY macro resolves to whitespace). – Evan Teran Aug 11 '09 at 18:46
  • 1
    I'd agree that your quote from the standard is more directly relevant, but it wan't there when I answered. Even if the example above isn't the same as what's asked about, the bit about the preprocessing directive needing to be in place at the start of phase 4 also disallows macros from explanding into useful preprocessing directives, even if 6.10.3.4(3) says so more directly. (in other words, even if I don't think my answer is incorrect, yours is clearly a better answer). – Michael Burr Aug 11 '09 at 18:54
  • Sorry, but I had to choose a good answer. Another +1 on your insightful comment to be as fair as possible, I hope you understand. – moala Aug 11 '09 at 23:24
  • No need to apologize - Evan's answer is definitely better. There's no need to apologize even if that weren't the case. – Michael Burr Aug 11 '09 at 23:36
1

All preprocessor directives are interpreted before macro expansion begins, so no, you cannot have a macro expand into an #include directive and have it be interpreted as such. Instead, it will be interpreted as (erroneous) C++ code.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • You might get this impression because many directives disable macro expansion of their arguments, but this is not true. Macro expansion happens concurrently with directive parsing. If it were true, #if would not work, and #undef would not have the effect people expect. – zwol Jul 11 '10 at 06:51