Принудительно включить один включаемый файл перед другим
Представь у меня два .hpp
файлы:
#ifndef _DEF_FILE_1_
#define _DEF_FILE_1_
inline void some_function_1(){
/*do stuff*/
}
#endif
а также
#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
Моя проблема возникает, когда я не знаю, в каком порядке файлы включены, например: в main.cpp
я могу иметь что-то вроде:
#include "file1.hpp"
#include "file2.hpp"
int main(){
some_function_2();
/*will call the function that uses some_function_1()*/
}
или же
#include "file2.hpp"
#include "file1.hpp"
int main(){
some_function_2();
/*will call the function that doesn't use some_function_1()*/
}
Есть ли способ убедиться, что как только file1.hpp
а также file2.hpp
включены, то some_function_2()
позвоню some_function_1()
?
PS: одним из решений было бы включить file1.hpp
в file2.hpp
но я не могу этого сделать, потому что я разработал код, который может зависеть или не зависеть от какой-то библиотеки, которую может иметь или не иметь конечный пользователь.
PPS: Единственное другое решение, которое я могу придумать (даже если я не знаю, как этого добиться), это "удалить" определение some_method_2()
когдаfile1.hpp
включен, а затем включить file2.hpp
,
4 ответа
Я считаю, что правильным решением было бы переписать some_function_2()
используя механизм и шаблон SFINAE вместо хитростей препроцессора. Таким образом, создание экземпляра будет происходить в файле cpp, где будет известно, если some_function_1()
существует и порядок включения не имеет значения.
Ваши пользователи должны знать, есть ли у них "какая-то библиотека" или у вас должен быть какой-то способ определить, присутствует ли эта библиотека. Таким образом, вы можете сделать что-то вроде:
В 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
Или, если возможно, полностью исключить file1.hpp и поставить some_function_1()
в месте нахождения #include "file1.hpp"
выше.
Теперь main.cpp должен включать только 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()*/
}
хотя, решение, которое избегает препроцессора, было бы лучше по моему мнению.
Если вы не знаете, существует ли файл и должны это обработать, то ни препроцессор c, ни C++ не проверяют наличие файлов. Это одна из причин инструментов настройки.
Вам нужно предварительно проверить эту информацию и установить ее перед компиляцией. Есть много способов сделать это. Обычно инструмент / скрипт, создает некоторые configure.h
Заголовок с соответствующими определениями создан. Например, содержащие такую строку #define FILE1_HPP_EXISTS 1
,
Тогда вы всегда можете рассчитывать на наличие configure.h
и он предоставит необходимую вам информацию.
Если ваш компилятор это позволяет, вы можете использовать _has_include
макрос:
Просто поменяю тебя file2.hpp
чтобы:
#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
Но имейте в виду, что это расширение для конкретного компилятора.