__has_cpp_attribute 不是 'function-like' 宏?

__has_cpp_attribute not a 'function-like' macro?

我正在尝试将 [[deprecated]] 属性引入我的代码库。然而,并不是所有我需要支持的编译器都支持这种语法(在attribute standardization proposal N2761中描述了不同编译器在标准化之前使用的各种方法)。因此,我试图在这个属性中有条件地编译,首先使用 __has_cpp_attribute 类似宏的函数,如果它可用的话,就像这样:

#if defined(__has_cpp_attribute) && __has_cpp_attribute(deprecated)
    #define DEPRECATED(msg) [[deprecated(msg)]]
#elif OTHER_COMPILER
    // ...
#endif

但是,我在使用 gcc version 4.9.2 (GCC)、命令行 gcc -std=c++14 cpp.cpp:

编译时遇到错误
cpp.cpp:1:56: error: missing binary operator before token "("
#if defined(__has_cpp_attribute) && __has_cpp_attribute(deprecated)

这个错误似乎表明定义了__has_cpp_attribute,但它不是宏函数。在 gcc 中有条件地编译 [[deprecated]] 属性的正确方法是什么?

GCC 4.9 没有 __has_cpp_attribute,并且 && 的短路行为不会扩展到允许无效构造跟随它。

也就是说,如果foo没有定义,

#if defined(foo) && foo(bar)

无效。

你要的是

#if defined(__has_cpp_attribute) 
    #if __has_cpp_attribute(deprecated)
        #define DEPRECATED(msg) [[deprecated(msg)]]
    #endif
#elif OTHER_COMPILER
    // ...
#endif

以便使用 __has_cpp_attribute 的条件位于如果未定义 __has_cpp_attribute 则跳过的组中。 (在跳过的组中时,预处理指令仅通过指令名称进行处理;其余标记将被忽略。)

T.C.的回答是对的,我想补充一点,你也可以为__has_cpp_attribute定义一个包装器,这往往会使多个测试更容易编写

#if defined(__has_cpp_attribute)
#  define MY_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr)
#else
#  define MY_HAS_CPP_ATTRIBUTE(attr) (0)
#endif

#if MY_HAS_CPP_ATTRIBUTE(attr)
#  define MY_DEPRECATED [[deprecated(msg)]]
#else
#  define MY_DEPRECATED
#endif

如果你走这条路,请使用命名空间而不是定义 __has_cpp_attribute。其他代码将检查是否 defined(__has_cpp_attribute) 并在可用时使用它,如果不可用则返回检查编译器版本。定义 __has_cpp_attribute 会破坏它。

当然,许多其他编译器支持某种语法来将符号标记为已弃用,即使它们不支持 __has_cpp_attribute,因此您可能会遇到更多情况;请参阅 Hedley 中的 HEDLEY_DEPRECATED 宏。它目前支持使用弃用属性的 GCC 4.5+、ICC 13+、armcc 4.1+ 和 TI 7.3+,使用弃用的 declspec 的 MSVC 13.10+ 和 Pelles 6.50+,以及使用 pragma 的 IAR,但支持可能会扩展到时间,我可能不会更新这个答案。