以下一段代码在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
功能。为什么会这样?
我看到你的代码存在一些问题:
-
只有当你
#include
了 -ed<version>
或<exception>
时,才会记录__cpp_lib_uncaught_exceptions
被定义(如果适用);你没有包括任何内容。在某个地方添加该功能测试上方#include <exceptions>
,它应该可以工作。 -
未定义宏时,编写的代码将在包含它的每个编译单元中重新定义
uncaught_exceptions()
,因为您在标头中进行了定义,并且没有将其inline
、static
或两者兼而有之,因此包括标头的每个.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++,至少似乎是这种情况。
因此,我假设您的问题在于选择的编译器选项,例如要编译的语言标准。