如何检查C++11支持?

111

有没有一种方法可以在编译时检测编译器是否支持C++11的某些特性?例如,类似于这样的内容:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

#error "Your compiler doesn't support variadic templates.  :("

#else

template <typename... DatatypeList>
class Tuple
{
    // ...
}

#endif

2
你可以创建一个名为 "assert_variadic_template_support.hpp" 的头文件,然后在其中编写 template <typename... Test> struct compiler_must_support_variadic_templates; 这样的代码。如果存在语法错误,编译器会很快地报错。当然,最好还是提供一个更加详细的错误信息。 - GManNickG
解决这个问题的“正确”方法是进行配置测试。 - Joseph Garvin
9个回答

127

有一个名为__cplusplus的常量,C++编译器应设置为所支持的C++标准的版本 请参见此处

#if __cplusplus <= 199711L
  #error This library needs at least a C++11 compliant compiler
#endif

在Visual Studio 2010 SP1中,它被设置为199711L,但我不知道供应商是否会如此大胆地增加它,即使他们只有(部分)编译器级别的支持,而没有带有所有C ++11更改的标准C ++库。

因此,另一个答案中提到的Boost定义仍然是唯一合理的方法,用于确定是否支持C++11线程和其他特定的标准部分。


42
C++11将__cplusplus的值设置为201103L,表示完全符合2011标准。它并不告诉你关于部分符合或编译器扩展的情况。如果__cplusplus被设置为201103L,那么要么编译器完全符合标准,要么它在欺骗你。如果不是,那么你无法确定它支持哪些功能。 - Keith Thompson
1
g++ 4.7.x(以及可能更新的版本)会在指定了“-std = c ++ 11”选项(也可以使用“-std = gnu ++ 11”)时设置此选项。尽管它们并不完全支持所有特性(4.8版本让我们更接近),但它们还是这样做了。请注意-编译器支持和标准库中提供的内容之间存在差距。目前,4.7.x和4.8.x都缺少regex支持,但那是一个库而不是编译器特性。 - Nathan Ernst
1
我想知道为什么这不是被接受的答案。此外,你可以使用这个建议来进一步改善你的答案,它非常好。 - Iharob Al Asimi
1
对我来说,Code::Blocks和Visual Studio都将__cplusplus的值设置为199711L,用于C++ 11。 - Donald Duck
3
严格来说,不是的。将 __cplusplus 设置为 199711L 的编译器并不符合 C++11 标准。它们可能有选项可以使它们正确地运行。 - Keith Thompson
显示剩余3条评论

42
根据C++11标准(§iso.16.8)所述:
“__cplusplus”名称在编译C++翻译单元时定义为值“201103L”。
有了该宏的值,您可以检查编译器是否符合C++11标准。
现在,如果您正在寻找一种标准方法来检查编译器是否支持任何C++11功能的子集,则我认为没有标准、可移植的方法。您可以查阅编译器文档或std库头文件以获取更多信息。

2
例如,static_assert在VS2010和所有c++11编译器中都受支持。因此,如果您检查__cplusplus的值大于或等于在VS2010中设置的值(即>= 199711L),则可以正常运行。 - Paolo M

36

我知道这是一个非常古老的问题,但这个问题可能经常出现,并且答案有点过时。

使用C++14标准的新编译器有一种标准的方法来检查功能,包括C++11功能。一个全面的页面位于https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

总之,每个功能都有一个标准宏定义,您可以使用#ifdef进行检查。例如,要检查用户定义的文字,您可以使用

#ifdef __cpp_user_defined_literals

2
我不知道这个。我认为这个简单的功能来得有点晚了,但它仍然非常有用,尤其是__has_include()宏。 - prapin

27
你可以使用这个:
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    cout << "C++11 is supported";
#else
    cout << "C++11 is not supported";
#endif

对于C++11,大多数编译器将__cplusplus宏设置为201103L。但是,视觉工作室根据其年龄和配置情况而定,将其设置为199711L,这是其他编译器在C++11之前使用的值。

此代码将_cplusplus宏与201103L进行比较,适用于除Visual Studio以外的所有编译器。如果编译器是Visual Studio,则检查Visual Studio的版本是否晚于2015年,这是Visual Studio完全支持C++11的第一个版本(对于Visual Studio 2015,_MSC_VER宏的值为1900,请参见this answer)。


2
这个答案是不正确的。对于使用GCC 4.8的g++ -std=c++98,它会错误地打印出“支持C++11”。 - pts
1
@pts 抱歉,只是一个打字错误。现在应该已经修复了。 - Donald Duck

25

为了支持C++14和其他版本,我们在GCC 5.2.1上进行了测试。

#include <iostream>

int main(){
        #if __cplusplus==201402L
        std::cout << "C++14" << std::endl;
        #elif __cplusplus==201103L
        std::cout << "C++11" << std::endl;
        #else
        std::cout << "C++" << std::endl;
        #endif

        return 0;
}

7

如果您不想使用Boost.Config,并且需要测试是否支持C++11的编译器,则可以检查常量__cplusplus的值。但是,编译器可能支持C++11标准的大多数流行特性,但它并不支持全部规范。如果您想启用对尚未完全符合C++11规范的特定Visual Studio编译器的支持,则可以使用以下代码片段进行在Visual Studio 2013中编译:

#if defined(_MSC_VER)
#   if _MSC_VER < 1800 
#       error This project needs atleast Visual Studio 2013
#   endif
#elif __cplusplus <= 199711L
#   error This project can only be compiled with a compiler that supports C++11
#endif

提供了Visual Studio编译器的完整版本列表,请查看如何检测我是否使用Visual Studio 2008编译代码

这个测试将在符合C++98或更高版本的任何C++编译器中成功,但不包括Microsoft C++编译器。 - Kaz

6
在传统的Linux/Unix世界中,通常使用autoconf来测试库和编译器功能和错误,并将它们放入config.h中,然后根据需要在文件中使用。

2
是的,autoconf可以用来测试功能,但是你必须让它生成适当的失败或成功宏,然后由上面的代码进行测试。因此,仅凭它本身,这个答案并不添加任何信息。 - Martin York
3
@LokiAstari说的并不是autoconf的工作原理。Autoconf提供宏,让您的configure脚本可以编译一个测试源文件,并根据编译的成功与否设置#define为0或1。diverscuba23的答案指出OP正在寻找解决真正问题的次优解,并提供了相关信息。 - Joseph Garvin
1
https://dev59.com/3mct5IYBdhLWcg3wqfP9 https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html - phs

4

快速历史

当这个问题在2011年2月被提出时,对于C++11的支持是不一致的。编译器需要时间来适应这个标准,因此在这段时间内,它们发布了部分支持。例如,一个编译器可能会实现可变参数模板,但不支持auto

如果你的代码依赖于C++11的一个子集,你没有一种标准的方法来询问编译器是否具体支持它们。

你可以check总体的C++11支持情况,使用#if __cplusplus >= 201103L,但:

  • 该常量及其含义直到后来标准被接受(即2011年8月)才正式确定。
  • 这太粗略了。编译器可能只在它们完全支持特性时将__cplusplus设置为201103L,而且没有人拥有全部特性支持。因此,如果你使用这个,你将不必要地拒绝大多数或全部人们想要用来编译你的代码的编译器。
一种实用的解决方案是使用第三方Boost.Config库,该库维护了一堆特性测试宏Boost.Config的维护者跟踪哪些编译器支持哪些特性,并为每个Boost.Config版本更新宏。
(关于Boost的这些内容基于早期已删除的答案,来自@James McNellis。)

今天

C++11

今天,每个主要编译器都有支持整个C++11标准的版本

如果你的代码需要任何C++11功能,现在可以合理地要求编译器支持所有C++11功能。因此,请使用#if __cplusplus >= 201103L。(有关此宏的标准参考,请参见Paulo M的答案。)但请注意,MSVC存在一些问题,请参见Donald Duck的答案

更进一步

自C++20以来,除了粗粒度的__cplusplus宏之外,您还可以#include <version>以获取一堆功能测试宏。这基本上是一个基于标准的替代方案Boost.Config
根据Jarryd的答案,这些宏实际上在至少一些2016年的C++14编译器中是可用的。

我真的希望有额外的宏来指定给定标准分配的相应版本号。例如,我希望下一个C++ ISO标准将__cplusplus1998指定为199711L,__cplusplus2011指定为201103L,__cplusplus2014指定为201402L等等。每个新的标准都会在列表中添加自己的宏。每次我想使用其中一个时,我都不得不查找这些值,而且很容易出现拼写错误。 - Peter - Reinstate Monica

1
当你要检查C++11库的可用性(而不是语言特性),例如<array>头文件时,你可以使用#if __has_include(<array>)
有时候检查#if __cplusplus >= 201103L会告诉你正在使用C++11,但其他设置,如Xcode中的标准库版本设置,可能仍然没有新库可用(大多数库在不同的名称下可用,如<tr1/array>)。

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