有没有办法检测是否包含 C++ 标准库的给定 header?

Is there a way to detect if a given header of the C++ Standard Library is included?

更具体地说,是否可以在编译时检测是否包含 C++ 标准 header 文件(比如 <complex>),并以 cross-plateform 和 cross-compiler ?我希望它至少可以与 C++11 一起使用,但是为了这个问题,任何 C++ 标准都可以吗?

我知道 C++ 标准库的实现依赖于编译器和操作系统,但是 header 是否有一个标准化的保护名称,一个我可以检查是否存在的宏?

我已经 运行 进入了这个:Detect usage of STL in C++ , which is a hack not to use the headers, and this : ,它用 C++17 特性来回答,实际上更多的是关于检测函数。

我想要的是能够在代码中的给定点编写一些预处理器指令,以判断是否包含 header(还)。我查看了<complex>(的一个实现)的源代码作为例子,定义了_GLIBCXX_COMPLEX,但可能只针对这个实现。

TL;DR:不,没有,除了 C++17 特性 #if __has_include(<complex>)。无论如何都没有定义的宏。

长答案:答案分为两部分。我从一些 header 中读到的内容,以及我 运行 使用不同编译器对不同 OS 进行的测试。

警告:我也会写关于 C 的文章,因为一些编译器使用相同的宏。我还使用快捷方式 'for C' 和 'for C++' 而不是 'when the header complex.h is included' 和 'when the header <complex> is included'.

好的,这是我目前的最佳答案。

关于 C 和 complex.h :

在C中,宏的存在 _Complex_I 是我认为应该在任何 complex.h header 中定义的唯一宏,因为它由 ISO C99 指定(参见 ISO/IEC 9899:1999/ TC3 文本)。 I 运行 的测试表明这是一个现实的假设。使用了一些额外的宏,例如 _COMPLEX_H 似乎是在使用 GCC 编译时定义的, 和 _C_COMPLEX_T 使用 MSVC 编译时。可能还有其他的,我没找到,欢迎补充。

但它是 C,不是 C++,两者不能混用。

关于 C++ 和 <complex> :

C++标准(ISO/CEI 14882:2011)没有指定这样的宏。事实上,它没有指定包含任何宏(乍一看)。 但是,它确实指定了 complex class 的存在,但这并没有回答问题。 根据我的阅读,_COMPLEX__C_COMPLEX_T 似乎在 <complex> header 中定义为 LLVM-clang 和 MSVC,也在 complex.h 中用于 apple 实现的 C 数学库 (libm)。
但是,我在 macOS 上使用 LLVM-clang 编译器进行的测试无法显示这些宏,而且我找不到读取该信息的文件。 我还发现 g++ 正在定义 _GLIBCXX_COMPLEX.

如果有人想用早于 C++17 的 C++ 来做到这一点,一种解决方案是使用给定的编译器和体系结构测试代码 运行。 这很糟糕,但这是我得到的最接近的答案。

测试:

我在这里给出了我 运行 在不同 OS 上的代码,编译器选项,它们的版本,以及它们提示的结果。 _Complex_I 确实为所有 C header 定义。
我无法使用 GCC 和 G++ 运行 在 macOS 上进行测试,但我敢打赌 _Complex_I 将使用 GCC 定义,_GLIBCXX_COMPLEX 使用 G++ 定义。

C++ 测试

G++ -std=c++11 v9.3.0 在 Ubuntu 20.04 上: _GLIBCXX_COMPLEX

G++ -std=c++11 v11.2.0 on windows 10(通过 Cygwin): _GLIBCXX_COMPLEX

MSVC 默认 c++11 选项 v14.29.xxxxx.x 在 windows 10 上: _C_COMPLEX_T _COMPLEX_

Apple LLVM-clang -std=c++11 v10.0.1 : None (并不意味着有 none,只是我不知道是哪个)

C++ 代码:

#include <iostream>
#include <complex>

int main(){

#ifdef _COMPLEX_
    std::cout << "_COMPLEX_" << std::endl;
#endif

#ifdef _C_COMPLEX_T
    std::cout << "_C_COMPLEX_T" << std::endl;
#endif

#ifdef _COMPLEX_H
    std::cout << "_COMPLEX_H" << std::endl;
#endif

#ifdef _Complex_I
    std::cout << "_Complex_I" << std::endl;
#endif

#ifdef _GLIBCXX_COMPLEX
    std::cout << "_GLIBCXX_COMPLEX" << std::endl;
#endif

    return 0;
}

C 测试:

GCC -std=c99 v9.3.0 在 Ubuntu 20.04 上: _Complex_I_COMPLEX_H

GCC -std=c99 v11.2.0 on windows 10(通过 Cygwin): _Complex_I_COMPLEX_H

MSVC -std=c99 v14.29.xxxxx.x 在 windows 10 上: _Complex_I_C_COMPLEX_T

Apple LLVM-clang -std=c99 v10.0.1 : _Complex_I

C 代码:

#include <stdlib.h>
#include <stdio.h>
#include <complex.h>

int main(){

#ifdef _COMPLEX_
    printf("_COMPLEX_\n");
#endif

#ifdef _C_COMPLEX_T
    printf("_C_COMPLEX_T\n");
#endif

#ifdef _COMPLEX_H
    printf("_COMPLEX_H\n");
#endif

#ifdef _Complex_I
    printf("_Complex_I\n");
#endif

#ifdef _GLIBCXX_COMPLEX
    printf("_GLIBCXX_COMPLEX\n");
#endif

    return 0;
}

总结一下:

MSVC 正在定义 _C_COMPLEX_T 使用的任何 C 或 C++,并且还为 C++ 定义 _COMPLEX__Complex_I 总是为 C 定义,而 G++ 似乎为 C++ 定义了 _GLIBCXX_COMPLEX 任何平台(测试要在 macOS 上完成)。