Home > Back-end >  C headers inclusion order, strange behaviour
C headers inclusion order, strange behaviour

Time:10-03

I'm writing some library and want to have some "optional" class methods (or just functions), declared or not, dependent on other library inclusion.

Say, I have a class SomeClass with method int foo(std::string). Sometimes it's very useful to also have similar method(s) which uses classes of another library the project is build upon - for example, sf::String or wxString, for SFML or wxWidgets accordingly.

In this case including SFML/System.hpp or even worse, wx/app.hpp or similar is absolutely NOT an option, because I want to have only methods for libraries that are already included. So, my first example must (as I suppose) work fine, but it's not:

main.cpp:

#include <SFML/System.hpp>       // FIRST, I include SFML base lib in the very first line.
#include <SFML/System/String.hpp>// to be 100% sure, I include SFML string class,
#include "a.h"                   // and ONLY AFTER that I include my own lib
// so inside the "a.h" file, the sf::String class *must* be already declared
main()
{   SomeClass x;
    x.foo("ABC");// error here: "undefined reference to `SomeClass::foo(sf::String)"
}

a.h:

#ifndef A_H_INCLUDED
#define A_H_INCLUDED
class SomeClass
{   public:
    #ifdef SFML_STRING_HPP
    int foo(sf::String str);// this method is declared, as expected
    #endif
};
#endif

a.cpp:

#include "a.h"
#ifdef SFML_STRING_HPP
int SomeClass::foo(sf::String str)
{   return 1;
}
#endif

The first question is: WHY? a.cpp includes a.h in the very beginning, and inside a.h the sf::String is declared, so why inside a.cpp after #include "a.h" it is not declared in fact?

I've tried to add #error OK right before #endif directive in a.cpp file, and this error is not fired.

Do I miss something about #include and .cpp / .h files?..

The second question is: How to fix that or work it around?

(And yes, I do a clean rebuild every time to avoid possible compiler bugs about partially changes sources, g likes it).

P.S: The same kind of "dependent" methods declarations works perfectly well with some template class - I suppose, it's because the implementation is within .h file where everything is OK about conditional compilation.

CodePudding user response:

a.c includes a.h that does not include <SFML/System/String.hpp>, thus SFML_STRING_HPP is not defined. Usually, what to include is set through compiler -D options. For example -DUSE_SFML_STRING

main.cpp

#include <SFML/System.hpp>       // FIRST, I include SFML base lib in the very first line.
#include "a.h"                   // and ONLY AFTER that I include my own lib
// so inside the "a.h" file, the sf::String class *must* be already declared
main()
{   SomeClass x;
    x.foo("ABC");// error here: "undefined reference to `SomeClass::foo(sf::String)"
}

a.h

#ifndef A_H_INCLUDED
#define A_H_INCLUDED

#ifdef USE_SFML_STRING
#include <SFML/System/String.hpp>
#endif

class SomeClass
{   public:
    #ifdef SFML_STRING_HPP
    int foo(sf::String str);// this method is declared, as expected
    #endif
};
#endif
  • Related