2

Imagine I have two .hpp files:

#ifndef _DEF_FILE_1_
#define _DEF_FILE_1_
inline void some_function_1(){
    /*do stuff*/
}
#endif

and

#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_
#ifdef _DEF_FILE_1_
inline void some_function_2(){
    /*do stuff using some_function_1()*/
}
#else
inline void some_function_2(){
    /*do the same stuff without using some_function_1()*/
}
#endif
#endif

My problem arises when I don't know in which order the files are included, e.g: in the main.cpp i can have something like :

#include "file1.hpp"
#include "file2.hpp"
int main(){
    some_function_2();
    /*will call the function that uses some_function_1()*/
}

or

#include "file2.hpp"
#include "file1.hpp"
int main(){
    some_function_2();
    /*will call the function that doesn't use some_function_1()*/
}

Is there a way to make sure that as soon as both file1.hpp and file2.hpp are included, then some_function_2() will call some_function_1()?

PS: One solution would be to include file1.hpp in file2.hpp but I can't do that because I developp a code that may or may not depend on some library that the end-user may or may not have.

PPS: The only other solution I can think of (even if I don't know how to achieve this) would be to "delete" the definition of some_method_2() when file1.hpp is included and then reinclude file2.hpp.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
PinkFloyd
  • 2,103
  • 4
  • 28
  • 47
  • AFAIK you can only instruct the users to include the header before yours, the preprocessor will go through the files in order and you can't really do anything about things that might follow your header. – Sami Kuhmonen Sep 17 '15 at 13:31
  • 3
    Why don't you make a third header, in which you `include` them in the right order, and use it in `main.cpp`? Nice username, btw. – SingerOfTheFall Sep 17 '15 at 13:33
  • @SingerOfTheFall Thx, my favourite band ;-). Because I don't know if the end-user has `file1.hpp`. – PinkFloyd Sep 17 '15 at 13:34
  • 2
    OT: Your include guards are [illegal](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – Baum mit Augen Sep 17 '15 at 13:40
  • @BaummitAugen: thanks, I was not aware of that – PinkFloyd Sep 17 '15 at 13:44
  • 1
    This seems like a terrible idea. You can very easily break the ODR and you don't really have very good control over which function implementation will be used. Why do you think you need to do this? There _must_ be a better way... – Lightness Races in Orbit Sep 17 '15 at 14:16
  • 1
    @LightnessRacesinOrbit add `static` to get round likely ODR violations I think. Still a bad idea. – Yakk - Adam Nevraumont Sep 17 '15 at 14:34
  • Pink, are the functions actually 0 argument functions? This matters. – Yakk - Adam Nevraumont Sep 17 '15 at 14:35
  • @Yakk, no, this was an example... I have many different function, with different arguments. I also have templates, classes... – PinkFloyd Sep 17 '15 at 14:44
  • @PinkFloyd Then the arguments can matter, as can the namespaces. ADL lookup is deferred to the point of template instantiation, while non-ADL lookup is done at template definition. Can you provide more detail? – Yakk - Adam Nevraumont Sep 17 '15 at 14:46

4 Answers4

1

I believe proper solution would be to rewrite some_function_2() using SFINAE mechanism and template instead of preprocessor tricks. That way instantiation will happen in cpp file where it would be known if some_function_1() exists and order of include will not matter.

Slava
  • 43,454
  • 1
  • 47
  • 90
0

Your users should know if they have "some library" or, you should have some way of determining if that library is present. So you could do something like:

In file2.hpp

#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_
#ifdef _DEF_HAS_SOME_LIBRARY_
#include "file1.hpp"
inline void some_function_2(){
    /*do stuff using some_function_1()*/
}
#else
inline void some_function_2(){
    /*do the same stuff without using some_function_1()*/
}
#endif
#endif

Or if possible eliminate file1.hpp entirely, and put some_function_1() in the location of #include "file1.hpp" above.

Now main.cpp should only include file2.hpp.

// optionally #define _DEF_HAS_SOME_LIBRARY_
#include "file2.hpp"
int main(){
    some_function_2();
    /*will call the function that uses some_function_1()*/
}

though, a solution that avoids the preprocessor would be better in my opinion.

YoungJohn
  • 946
  • 12
  • 18
  • What do you mean by `_DEF_HAS_SOME_LIBRARY_`, how can I check that ? – PinkFloyd Sep 17 '15 at 13:50
  • 1
    You say the problem is that "you don't know the order of the files included", but someone must know. Either you have an alternate means of determining if some_library is accessible on the machine, or whoever is trying to include "file2.hpp" has that knowledge. Before including "file2.hpp" the user of "file2.hpp" should either define _DEF_HAS_SOME_LIBRARY_ or not depending on whether or not they want the functionality enabled of some library. – YoungJohn Sep 17 '15 at 14:03
0

If you don't know whether the file exists and need to handle that, well, neither c nor c++ preprocessor handle file existence checks. This is one of the reasons behind configure tools.

You need to probe for this information beforehand, and set it before compiling. There many ways to do it. Usually a tool / script, creates some configure.h header with appropriate defines is created. E.g. containing such line #define FILE1_HPP_EXISTS 1.

Then you can always rely on presence of configure.h and it will provide information you need.

luk32
  • 15,812
  • 38
  • 62
0

If your compiler allows it you might use the _has_include macro:

Just change you file2.hpp to:

#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_

#if defined(__has_include) && __has_include("file1.hpp")
# include "file1.hpp"
inline void some_function_2() {
    /*do stuff using some_function_1()*/
}
#else
inline void some_function_2() {
    /*do the same stuff without using some_function_1()*/
}
#endif
#endif

But keep in mind that this is a compiler specific extension.

Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49