Valid uses for C++ include guards besides, well, include-guarding?

636 views Asked by At

This question is one of several that discuss naming conventions for C++ include guards. The person asking that question thinks that this naming convention:

#ifndef FOO_H
#define FOO_H

// ...

#endif

is a bit non-intuitive when taken by itself (what does FOO_H mean?) and I tend to agree.

Others say that, barring the need to add more stuff for better collision avoidance (like PROJECTNAME_FOO_H_SDFFGH69876GF), the name FOO_H is just fine because it's clear from its context what its purpose is (namely, it's at the beginning of the files of the same name and it's clear that it's an include guard).

I could buy this if the only purpose of having FOO_H would be to guard against multiple inclusion, but are there conditions for which I'd want to have FOO_H elsewhere in the files? I'd think conditional compilation would be a good reason, in which case naming it something like FOO_H_INCLUDED would be clearer.

Are there straightfoward uses akin to this, or should I avoid repurposing the include guards?

5

There are 5 answers

0
David Rodríguez - dribeas On BEST ANSWER

I think the question is flawed in itself. The term include guards refers to #defines and checks for #defined in the particular use of guarding against multiple inclusion, which is as much to say that is the only use for that.

Now taken a little more generally, defines and conditional compilation can be used for other things, like writing bits of code that are platform dependent and will only get compiled under some circumstances...

Whether FOO_H or FOO_H_INCLUDED is better, I will always say that the later is the most expressive, and then I will go back to vi and type FOO_H in my next foo.h header. Again, as I mentioned in a comment on the other question, you grow used to the pattern:

#ifndef XXXXXXXXX
#define XXXXXXXXX

#endif

as the first two and last line in a file and you end noticing. That is until it bites back if you have reused the same name...

0
Steve Jessop On

For repurposing: unless the entire contents of the file are surrounded by the ifndef/define/endif, then FOO_H isn't really a file include guard, it's only guarding part of a file. So possibly it shouldn't be named after the whole file. Recursive inclusion of the same file is one situation where this can come up.

That said, I suspect that even so, it should be pretty obvious what the define is for (anyway, more obvious that whatever tricksy thing it is you're doing that isn't simple include guarding). Anywhere you see the pattern ifndef FOO/define FOO, or even just ifndef FOO / define lots of stuff, a simple comment can make the meaning of FOO obvious if it isn't already.

If any part of the question is whether the token FOO_H might ever be used for some other purpose: I guess if you have a file somewhere called uppercase.h which uses UPPERCASE_H as an include guard, then that could conceivably clash with someone's rot13.h, containing #define UPPERCASE_A ('N'), etc. Silly example, but if you were defining properties of letters in a header file then it's not ridiculous to think that some of them might end in _H.

More realistically, I've had projects with include files having the same basename in different directories.

So, regardless of the issue of context and repurposing, I wouldn't use FOO_H as an include guard.

1
Alexandre C. On

Sometimes, I use this for "implementation" header files. Actual naming scheme for guards may differ.

#ifndef FOO_IMPL_H
#define FOO_IMPL_H

#ifndef FOO_H
#error Don't include this directly
#endif

// Ugly implementation of the stuff in foo.h, with an uncountable
// number of template and typename keywords

#endif 
1
Marlon On

In my opinion, include guards should be include guards and nothing more. If you want conditional compilation, I would define something else. If you were throwing around #if defined(FOO_H) in your code, I think people would find this strange since _H usually indicates an include guard.

One thing I can think of though is checking if the file has already been included (duh!) so that you don't have to include the file yourself. I'm not sure if this would speed up compilation or not, in comparison to forward declarations or #pragma once

In main.cpp:

#include "bar.h" // comment this line to see the difference
#include "foo.h"

int main()
{
    return 0;
}

In bar.h:

#ifndef BAR_H
#define BAR_H

class BarClass
{
};

#endif

In foo.h:

#ifndef FOO_H
#define FOO_H

#if !defined(BAR_H)
#error bar h was not included // forgot how to do compiler warnings...
#include "bar.h" // we should include the file
#else
#error bar h was included // same thing, should be changed to warning
#endif

// do something with BarClass

#endif FOO_H
0
Fred Nurk On

I'd think conditional compilation would be a good reason, in which case naming it something like FOO_H_INCLUDED would be clearer.

I only see one very narrow use here to avoid including a header when you only need a forward declaration, but want to skip the forward declarations if the header has previously been included.

However, this is not a bottleneck in compiling C++ today, and the added confusion over either always having the forward declarations or always including the header is not worthwhile.

Even if you needed tons – and I mean hundreds to thousands of lines of these forward declarations – so that it did become worthwhile, you'd be better off with a dedicated header, similar to <iosfwd>, rather than maintaining this in multiple places.