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
