当 GCC 不提供__cpp_lib_uncaught_exceptions功能时?



以下一段代码在Alpine Linux上不起作用:

#ifndef __cpp_lib_uncaught_exceptions
namespace std {
int uncaught_exceptions() noexcept {
return std::uncaught_exception();
}
}
#endif

错误:

[ 89%] Linking CXX executable AdsLibTest.bin
/usr/lib/gcc/x86_64-alpine-linux-musl/11.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: /usr/lib/gcc/x86_64-alpine-linux-musl/11.2.1/../../../../lib/libstdc++.a(eh_catch.o): in function `std::uncaught_exceptions()':
/home/buildozer/aports/main/gcc/src/gcc-11.2.1_git20220219/libstdc++-v3/libsupc++/eh_catch.cc:149: multiple definition of `std::uncaught_exceptions()'; CMakeFiles/AdsLibTest.bin.dir/main.cpp.o:main.cpp:(.text+0x8d0): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [_deps/ads-build/AdsLibTest/CMakeFiles/AdsLibTest.bin.dir/build.make:98: _deps/ads-build/AdsLibTest/AdsLibTest.bin] Error 1

看起来 GCC 不提供__cpp_lib_uncaught_exceptions功能。为什么会这样?

我看到你的代码存在一些问题:

  1. 只有当你#include了 -ed<version><exception>时,才会记录__cpp_lib_uncaught_exceptions被定义(如果适用);你没有包括任何内容。在某个地方添加该功能测试上方#include <exceptions>,它应该可以工作。

  2. 未定义宏时,编写的代码将在包含它的每个编译单元中重新定义uncaught_exceptions(),因为您在标头中进行了定义,并且没有将其inlinestatic或两者兼而有之,因此包括标头的每个.cpp文件最终都会获得自己的可导出定义。如果标头中不包含必要的标头,是否定义了该功能测试宏将取决于每个.cpp文件是否包含<exception>/<version>,以及它是在包含标头之前还是之后执行此操作。如果它们不统一,则某些文件可以获取标头的定义,而其他文件则可以获取内置定义。

将声明添加到namespace std原因(少数特定例外)未定义的行为。没有理由认为这应该有效,即使编译器确实正确报告它不提供std::uncaught_exceptions

特别是,如果标准库实现支持std::uncaught_exceptions并且文件是在语言标准设置为低于 C++17 的情况下编译的,那么功能测试将声称std::uncaught_exceptions不受支持,但标准库.a/.so仍可能为其提供定义。这将导致重复定义错误。

正如@ShadowRanger所指出的,函数定义上也可能缺少一个inline,因为它可能包含在多个翻译单元中的多个翻译单元中。

此外,为了使用功能测试宏,必须包含<version>(自 C++20 起)或与该功能对应的头文件,例如在本例中为<exception>。否则,不会定义宏,并且功能检查将始终失败。似乎标头不包括<exception>,但包含<stdexcept>,这在技术上是不够的。但是,实际上,<stdexcept>可能会包括<exception>,因此可能仍然有效。对于当前的libstdc++,至少似乎是这种情况。

因此,我假设您的问题在于选择的编译器选项,例如要编译的语言标准。

最新更新