Luke B.
Luke B.

Reputation: 1288

Is there a case where including the same header twice is actually helpful?

Creating header guards for my h/hpp files has always been standard practice for me, but I wonder, why is it even possible to include de same file twice? Is there a case where you actually need unprotected headers?

Upvotes: 10

Views: 1705

Answers (6)

iNyuu
iNyuu

Reputation: 72

Imagine you are writing your own template array wrapper (elements are pointers) for your tiny engine where array can either be:

  • dynamic or static
  • indexes/order matters or not
  • you can delete an element (not just remove from the array) outside the array or inside

so with this you can either create one class where all this handled but it would always check for what we can or cannot do. best is to create separate classes but here we have so much same code between them you could (if not careful) either make a mistake in one of them functions plus adding a new function would be slower.

so best is to take use of the "Parameterized" header files (as AnT stated) and simply create classes like

  • Cl_Array_Dy, Cl_Array_DyIn, Cl_Array_DyDel, Cl_Array_DyInDel
  • Cl_Array_St, Cl_Array_StIn, Cl_Array_StDel, Cl_Array_StInDel

code example:

// TestDfM.h

#ifndef TEST_DFM_H
#   define TEST_DFM_H

    // first we need to make sure neither of these is defined
#   ifdef Df_ARG1
#       undef Df_ARG1
#   endif
#   ifdef Cl_First
#       undef Cl_First
#   endif
#   ifdef Cl_Second
#       undef Cl_Second
#   endif
#   ifdef Df_FIRST
#       undef Df_FIRST
#   endif
#   ifdef Df_SECOND
#       undef Df_SECOND
#   endif
#   ifdef TEST_DF_H
#       undef TEST_DF_H
#   endif

    // we need this
#   define Df_FIRST 1
#   define Df_SECOND 2

    // first class creation
#   define Df_CLASS Df_FIRST
#   define Df_ARRAY Cl_First
#   include "TestDf.h"

    // cleanup (after 1st)
#   undef Df_CLASS
#   undef Df_ARRAY

    // second class creation
#   define Df_CLASS Df_SECOND
#   define Df_ARRAY Cl_Second
#   define Df_ARG1
#   include "TestDf.h"

    // cleanup (after 2st)
#   undef Df_CLASS
#   undef Df_ARRAY
#   undef Df_ARG1

    // so we theoretically cannot include TestDf.h anymore (anywhere)
#   define TEST_DF_H

#endif // TEST_DFM_H

// TestDf.h

// nothing to do here if the main header for this was not included
// also we should only call this inside the main header
#if defined(TEST_DFM_H) && !defined(TEST_DF_H)
#   include "../Includes.h"

    class Df_ARRAY {
    public:
        int m_shared;

#   ifndef Df_ARG1
        Df_ARRAY(int in_shared=0) { m_shared= in_shared; }
        void f_info() { printf("out: %d\n", m_shared); }
#   else
        int m_x;
        Df_ARRAY(int in_shared=0, int in_x= 7) { m_shared= in_shared; m_x= in_x; }
        void f_info() { printf("out: %d [also has %d]\n", m_shared, m_x); }
#   endif

#   if Df_CLASS == Df_FIRST
        void f_class() { printf("1st\n"); }
#   elif Df_CLASS == Df_SECOND
        void f_class() { printf("2nd\n"); }
#   endif
    };

#endif // TEST_DFM_H

// Main.cpp

#include "Array/TestDfM.h"

int main(int argc, char** argv) {
    Cl_First a(6);
    Cl_Second b(2);
    a.f_class(); // 1st
    b.f_class(); // 2nd
    a.f_info(); // out: 6
    b.f_info(); // out: 2 [also has 7]
    return 0; }

Upvotes: 2

AnT stands with Russia
AnT stands with Russia

Reputation: 320777

"Parameterized" header files can be used to simulate C++-ish-style templates in C. In such cases the header file will depend on a number of macros ("template parameters"). It will generate different code depending on the actual "value" of these macros.

So, the typical usage of such header would look as a sequence of "template parameter" macro definitions followed by the #include directive, followed by another sequence of "template parameter" macro definitions followed by the same #include, and so on.

https://stackoverflow.com/a/7186396/187690

When using this technique you will see header files without any include guards or header files with include guards that cover only a portion of the file.

Upvotes: 10

Dietmar Kühl
Dietmar Kühl

Reputation: 154045

Header files are just textually included whenever they are encountered. There isn't any real reason why they can't be included more than once. If headers are only used for declaration and no definitions (and no declarations of templates with default arguments) there isn't even anything problematic with including them more than once.

That said <cassert> is the canonical example of including a file more than once: You can change the definition of NDEBUG and get different behavior from the assert() macro within one translation unit.

Now having something like include_once which includes a file just once turns out to be not as trivial as people tend to think. Here is an example where it isn’t clear how often foo.h should be included:

#include_once "foo.h"
#include_once "./foo.h"
#include_once "bar/foo.h"

Assuming include_once includes each file just once, how often should foo.h be included? All three files can easily refer to the same physical file but this may not readily be visible, e.g., because one is a link to another one. It seems best to give the control to the programmer how can control how often they end up being used.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 755064

In C:

#undef NDEBUG
#include <assert.h>

...code using active asserts...

#define NDEBUG
#include <assert.h>

...code using disabled asserts...

Rinse and repeat. The analogue in C++ uses the header <cassert> instead.

So, sometimes there are reasons to include a header twice. Not often, but there are reasons to do so.

Upvotes: 7

Luchian Grigore
Luchian Grigore

Reputation: 258678

Cases like these are rare, and when they do exist, a re-design is better suited anyway. One I can think of is headers that amass declarations:

//functions.h
virtual void foo();
virtual void goo();

//classes.h
class A : public Base
{
    #include "functions.h"
};

class B : public Base
{
    #include "functions.h"
};

This wouldn't work if functions.h had include guards, but then again, this is pretty awkward code...

Upvotes: 2

Pubby
Pubby

Reputation: 53097

Stuff like Boost.PP does lots of tricks by including headers multiple times. It essentially allows for primitive forms of loops.

Also, X-Macros are designed to be included multiple times.

Upvotes: 7

Related Questions