C++ 是否可以用两种不同的语言标准编译一个项目?

C++ 是否可以用两种不同的语言标准编译一个项目?,c++,C++,我有一个严格用C++14编写的项目,我想在另一个项目C++17中使用它。在C++17中删除了C++14的一些功能,如 有没有办法一起使用和编译这两个代码基?这个项目足够大,使得重构不实用。 < P>是的,您可以检测C++版本并有条件编译: void foo(){ #如果uu cplusplus>=201703L //为C++17编写的代码如下 #否则 //为C++14编写的代码如下 #恩迪夫 } \uu cplusplus宏的完整列表如下所示: #如果u cplusplus>=199711L/

我有一个严格用C++14编写的项目,我想在另一个项目C++17中使用它。在C++17中删除了C++14的一些功能,如


有没有办法一起使用和编译这两个代码基?这个项目足够大,使得重构不实用。

< P>是的,您可以检测C++版本并有条件编译:

void foo(){
#如果uu cplusplus>=201703L
//为C++17编写的代码如下
#否则
//为C++14编写的代码如下
#恩迪夫
}
\uu cplusplus
宏的完整列表如下所示:

#如果u cplusplus>=199711L//C++98
#如果uu cplusplus>=201103L//C++11
#如果uu cplusplus>=201402L//C++14
#如果uu cplusplus>=201703L//C++17
#如果uu cplusplus>=202002L//C++20
请注意,这会导致各种问题:

  • 除非分别为C++14和C++17编译测试,否则不可能像这样测试代码
  • IDE甚至可能不会在已删除的预处理块中显示警告或错误
  • 您需要维护同一代码的两个独立版本
因此,如果可以的话,可以想出一个在两个版本中都能工作的解决方案,或者至少使用尽可能少的块。如果只想删除单个关键字,则考虑以下解决方案:

#如果uu cplusplus>=201703L//C++17
#定义抛出(异常)noexcept(错误)
#否则
#定义抛出(异常)抛出(异常)
#恩迪夫
//现在,您可以在C++14和C++17中这样使用它:
void fun()抛出(MyException);

这将是特定于平台的:可以想象,根据命令行上指定的标准选择了实质上不同的标题,等等

也就是说,Jonathan Wakely的回答向您保证,如果您远离旧编译器中不稳定的特性,那么gcc在设计上就不会有这样的问题

乔纳森的根本原因是,GCC中的C++标准实现一旦被声明为稳定的,就不会用选定的C++标准来改变ABI(即向外面向类型的定义、名称的修改),甚至在编译器版本之间也不会改变。 因为翻译单元之间的所有交互都必须限制在最小的通用标准版本,所以没有问题:如果指定C++17,C++11特性不会改变。C++17 TUs中较新的功能无法用于与早期标准TUs的通信,因为它们还不可用,因此也没有问题。如果您能够重新编译,最安全的建议是:

  • 最好使用相同的std::string版本(可以在编译时从命令行控制)
  • 使用相同的libstdc++
  • 使用相同的gcc版本(并通过命令行控制每个TU使用的语言标准)

  • 其他编译器遵循类似的兼容性策略是有意义的。

    完全抛弃动态异常规范不是更容易吗?它毕竟是您的项目,所以您可以更改它。如果您仅在cpp文件中使用不再受支持的功能,则这是可以的。毕竟,所有东西都被编译成二进制级别。但你不能以这种方式重用头文件。这不全是关于动态异常规范的问题,代码中还有另一个无法用C++17编译的问题。要清楚,你需要将C++14和C++17代码链接到一个可执行文件中,对吗?这是否得到支持取决于平台的具体情况,我可以想出很多不起作用的原因。(例如,
    std::string
    的实现可能完全不同,因此C++14代码会将
    std::string
    传递给C++17代码吗?)这导致了更大的问题,我更喜欢重构代码。@Ghasemramezan我不确定接下来要告诉你什么。动态异常规范是函数头的一部分,当您将其包含到C++17代码中时,它将不会编译。要么像这样有条件地编译,要么重构所有这些规范。您还可以在宏中捕获异常规范之类的功能,我会将其添加到答案中。但是,当您需要从C++17库调用C++14库的函数时,这如何解决问题?您可以很好地链接到它,但是如果使用了在C++17.@J.Schultke中删除的功能,头include仍然会导致编译器错误。对于使用不同标准选项编译的两个文件之间的调用,您只能使用这两个标准的公共子集。通常这只是意味着c++14文件不能调用/使用c++17函数或类型,但在c++17不向后兼容的情况下,也适用相反的情况。由于在C++14中,异常规范iiuc不是函数类型()的一部分,因此您可以简单地将其包装在预处理器条件宏中,而在C++17中,该宏为空。