能够使用两种不同的语言标准编译一个项目吗?

4
我有一个项目,严格使用C++14编写,并且我想在另一个使用C++17的项目中使用它。一些C++14的特性,比如动态异常规范在C++17中被移除了。
有没有办法同时使用和编译这两个代码库?这个项目足够大,使得重构变得不切实际。

1
放弃动态异常规范完全不是更容易吗?毕竟这是你的项目,你可以改变它。 - Nicol Bolas
1
如果你只在cpp文件中使用不再支持的功能,那么这是可以的。毕竟所有东西都会被编译成二进制级别。但是你不能以这种方式重用头文件。 - freakish
并不全是关于动态异常规范,代码还存在另外的问题,这些问题在 C++17 中可能无法编译。 - Ghasem Ramezani
清楚地说,您需要将C++14和C++17代码链接成单个可执行文件,是这样吗?无论是否支持都将取决于特定的平台,我可以想到许多原因它不起作用。(例如,std :: string的实现可能完全不同,那么当C++14代码将std :: string传递给C++17代码时会发生什么?) - David Schwartz
2个回答

2
这将是平台特定的:可以根据命令行上指定的标准选择不同的头文件等。
话虽如此,这里有一个Jonathan Wakely的答案(来自这里),他向您保证,如果您远离旧编译器中不稳定的功能,则使用gcc不应该出现此类问题。
根据Jonathan的说法,C++标准在gcc中的实现一旦声明为稳定状态,就不会随着所选的C++标准甚至编译器版本而更改其ABI(即,外部类型定义、名称重整),因此没有问题。
由于所有翻译单元之间的交互必须限制在最小公共标准版本上,因此没有问题:如果指定了C++17,则C++11功能不会更改。 C++17 TU中的新功能不能用于与早期标准TU的通信,因为它们还不可用,因此也没有问题。 如果您能够重新编译,则最安全的建议是:
  1. 最好使用相同的std :: string版本(可以在编译时从命令行控制)。
  2. 使用相同的libstdc ++。
  3. 使用相同的gcc版本(并通过命令行控制每个TU使用的语言标准)。
其他编译器遵循类似的兼容性策略是有意义的。

当你需要从C++17库调用C++14库的函数时,这怎么解决问题呢?你可能能够很好地链接它,但如果使用了在C++17中删除的功能,则头文件包含仍将导致编译器错误。 - Jan Schultke
对于使用不同标准选项编译的两个文件之间的调用,您只能使用两种标准的公共子集。 通常情况下,这意味着 c++14 文件无法调用/使用 c++17 函数或类型,但在 c++17 不向后兼容的情况下,相反的情况也适用。由于在 C++14 中,异常规范(iiuc)并非函数类型的一部分(https://en.cppreference.com/w/cpp/language/noexcept_spec),因此您可以将其简单地包装在一个预处理器条件宏中,该宏在C++17中为空。 - Peter - Reinstate Monica

1
是的,你可以检测C++版本并进行条件编译。
void foo() {
#if __cplusplus >= 201703L
    // code written for C++17 goes here
#else
    // code written for C++14 goes here
#endif
}

完整的__cplusplus宏列表如下:
#if __cplusplus >= 199711L // C++98
#if __cplusplus >= 201103L // C++11
#if __cplusplus >= 201402L // C++14
#if __cplusplus >= 201703L // C++17
#if __cplusplus >= 202002L // C++20

请注意,这会引起各种问题:
- 除非你将测试代码分别编译为C++14和C++17,否则无法测试这样的代码。 - 你的IDE可能甚至不会显示已删除的预处理块中的警告或错误。 - 你需要维护两个独立版本的相同代码。
因此,如果可能的话,请提出一个在两个版本中都能工作的解决方案,或者至少尽量减少这样的块。如果你只想删除一个关键字或类似的内容,请考虑以下解决方案:
#if __cplusplus >= 201703L // C++17
#define THROWS(...) noexcept(false)
#else
#define THROWS(...) throw(__VA_ARGS__)
#endif

// now you can use it like this in both C++14 and C++17:
void fun() THROWS(MyException);

这让我面临了更大的问题,我更喜欢重构代码。 - Ghasem Ramezani
@GhasemRamezani 不确定该怎么告诉你。动态异常说明是函数头的一部分,当你将其包含到C++17代码中时,它不会编译。你需要像这样有条件地进行编译,或者需要重新设计所有这些说明。你也可以通过宏来捕获异常说明等特性,我将在答案中添加这个。 - Jan Schultke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接