【问题标题】:Force one include file to be included before another强制将一个包含文件包含在另一个之前
【发布时间】:2015-09-17 13:27:12
【问题描述】:

假设我有两个.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.hppfile2.hpp 包括在内,那么some_function_2() 将调用some_function_1()

PS:一种解决方案是将file1.hpp 包含在file2.hpp 中,但我不能这样做 那是因为我开发了一个可能依赖于也可能不依赖于某个库的代码 最终用户可能有也可能没有。

PPS:我能想到的唯一其他解决方案(即使我不知道如何 实现这一点)将是“删除”some_method_2() 的定义时 包含file1.hpp,然后重新包含file2.hpp

【问题讨论】:

  • AFAIK 您只能指示用户在您的标题之前包含标题,预处理器将按顺序检查文件,您无法对标题后面的内容做任何事情。
  • 你为什么不做第三个标题,你include它们以正确的顺序,并在main.cpp中使用它?不错的用户名,顺便说一句。
  • OT:您的包含守卫是illegal
  • 这似乎是个糟糕的主意。您可以很容易地破坏 ODR,并且您并不能很好地控制将使用哪个函数实现。为什么你认为你需要这样做? 必须有更好的方法...
  • @LightnessRacesinOrbit 添加static 以绕过我认为可能的 ODR 违规行为。还是个坏主意。

标签: c++ conditional-compilation


【解决方案1】:

我相信正确的解决方案是使用 SFINAE 机制和模板而不是预处理器技巧来重写 some_function_2()。这样实例化将发生在 cpp 文件中,如果 some_function_1() 存在并且包含顺序无关紧要。

【讨论】:

    【解决方案2】:

    您的用户应该知道他们是否有“某个库”,或者您应该有某种方法来确定该库是否存在。所以你可以这样做:

    在文件 2.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()*/
    }
    

    不过,在我看来,避免预处理器的解决方案会更好。

    【讨论】:

    • _DEF_HAS_SOME_LIBRARY_ 是什么意思,我该如何检查?
    • 你说问题是“你不知道包含的文件的顺序”,但肯定有人知道。要么你有另一种方法来确定机器上是否可以访问 some_library,要么试图包含“file2.hpp”的人有这个知识。在包含“file2.hpp”之前,“file2.hpp”的用户应该定义 DEF_HAS_SOME_LIBRARY,这取决于他们是否希望启用某些库的功能。
    【解决方案3】:

    如果您不知道文件是否存在并且需要处理它,那么 c 和 c++ 预处理器都不会处理文件存在检查。这是配置工具背后的原因之一。

    您需要事先探测此信息,并在编译前进行设置。有很多方法可以做到这一点。通常是一个工具/脚本,创建一些带有适当定义的configure.h 标头。例如。包含这样的行#define FILE1_HPP_EXISTS 1

    那么您始终可以依赖configure.h 的存在,它会提供您需要的信息。

    【讨论】:

      【解决方案4】:

      如果您的编译器允许,您可以使用_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
      

      但请记住,这是特定于编译器的扩展。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-08
        • 1970-01-01
        • 1970-01-01
        • 2011-10-27
        • 2012-05-01
        • 2011-01-21
        相关资源
        最近更新 更多