C ++标记已弃用


147

我想在便携式C ++中弃用一个接口中的方法。当我用谷歌搜索时,我得到的只是一个针对微软的解决方案。#pragma已弃用__declspec(已弃用)

二等奖解决方案是ifdef MSVC和GCC解决方案。
谢谢

Answers:


193

在C ++ 14中,您可以使用[[deprecated]]属性将功能标记为已弃用(请参见7.6.5 [dcl.attr.deprecated])。

属性令牌 deprecated可以用来标记的名称和它的使用仍然是允许的实体,但不鼓励出于某种原因。

例如,foo不推荐使用以下功能:

[[deprecated]]
void foo(int);

可以提供一条消息,描述不赞成使用名称或实体的原因:

[[deprecated("Replaced by bar, which has an improved interface")]]
void foo(int);

该消息必须是字符串文字。

有关更多详细信息,请参见“在C ++ 14中标记为已弃用”


您可以在宏中使用[[deprecated]]吗?
Daniel Ryan

2
@Zammbi您应该能够,因为宏在编译之前由预处理器处理。[[deprecated]]应该出现(并让编译器输出相关的警告),在该位置评估宏。
弗洛里安·卡斯泰拉内

129

这应该可以解决问题:

#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif

...

//don't use me any more
DEPRECATED(void OldFunc(int a, float b));

//use me instead
void NewFunc(int a, double b);

但是,如果函数返回类型的名称中带有逗号,则会遇到问题,例如std::pair<int, int>,这将由前处理器解释为将2个参数传递给DEPRECATED宏。在这种情况下,您将必须键入def返回类型。

编辑:简单(但可能不太广泛兼容)的版本在这里


6
最好是#define DEPRECATED(func)func
不是#error

1
mxp:弃用只是警告,因此,我只需要一个不支持该警告的警告即可。
Leon Timmermans

1
是的,我会去“#警告您需要为此编译器实现DEPRECATED”或类似的东西。如果那是不可能的,那么搬运工可以#define DEPRECATED(FUNC)FUNC,然后不使用它。
史蒂夫·杰索普

2
不幸的是,没有在C ++中输出编译警告的标准方法:P #pragma消息将必须执行。
Michael Plates

3
gcc的属性语法允许该属性位于与__declspec(deprecated)现在相同的位置,因此可以简化宏。
bames53 2012年

57

这是我2008年答案的简化版本:

#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif

//...

//don't use me any more
DEPRECATED void OldFunc(int a, float b);

//use me instead
void NewFunc(int a, double b);

也可以看看:


17
您如何[[deprecate]]弃用宏?:-)
graham.reeds,2015年

3
我看不出这两个答案之间有什么显着差异。您为什么第二次发布?
托马什Zato -恢复莫妮卡

4
您不必将其包装在函数周围,DEPRECATED void foo(...);而是用它代替DEPRECATED(void foo(...));
dshepherd

12
您应该已经编辑了2008年的答案,而不是发布新的答案。
Yakov Galka '16

4
这可能不如我的其他答案广泛兼容,因此我将其单独添加。
Michael Plates


8

这是2018年的更完整答案。

如今,许多工具不仅使您可以将某项标记为已弃用,还可以提供消息。这使您可以告诉人们何时不推荐使用某些产品,甚至可以将其指向替代产品。

编译器支持仍然有很多种类:

  • C ++ 14支持[[deprecated]]/[[deprecated(message)]]
  • __attribute__((deprecated)) 由GCC 4.0+和ARM 4.1+支持
  • __attribute__((deprecated))__attribute__((deprecated(message)))支持:
    • 海湾合作委员会4.5+
    • 伪装成GCC 4.5+的几种编译器(通过设置__GNUC__/ __GNUC_MINOR__/__GNUC_PATCHLEVEL__
    • 英特尔C / C ++编译器至少可以恢复到16(您不能信任__GNUC__/__GNUC_MINOR__,他们只是将其设置为已安装的GCC的任何版本)
    • ARM 5.6以上
  • MSVC支持 __declspec(deprecated)从13.10开始(Visual Studio 2003)
  • __declspec(deprecated(message))从14.0开始支持MSVC (Visual Studio 2005)

您还可以[[gnu::deprecated]]在C ++ 11的最新版本的clang中使用,具体取决于__has_cpp_attribute(gnu::deprecated)

我在Hedley中有一些宏可以自动处理所有这些宏,这些宏我一直保持最新,但是当前版本(v2)如下所示:

#if defined(__cplusplus) && (__cplusplus >= 201402L)
#  define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
#  define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
#elif \
  HEDLEY_GCC_HAS_EXTENSION(attribute_deprecated_with_message,4,5,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(5,6,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
#elif \
  HEDLEY_GCC_HAS_ATTRIBUTE(deprcated,4,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)
#  define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_DEPRECATED(since) _declspec(deprecated)
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
#else
#  define HEDLEY_DEPRECATED(since)
#  define HEDLEY_DEPRECATED_FOR(since, replacement)
#endif

我将其保留为练习,以弄清楚如何摆脱*_VERSION_CHECK*_HAS_ATTRIBUTE如果您不想使用Hedley的话宏(我写Hedley的主要目的是因为我不必定期考虑这一点)。

如果使用GLib,则可以使用G_DEPRECATEDG_DEPRECATED_FOR宏。它们不像Hedley的那样健壮,但是如果您已经使用GLib,则无需添加任何内容。


4

在处理可移植项目时,几乎不可避免地需要在某个时候为一系列平台提供一部分预处理的替代品。#ifdef这个#ifdef that等等。

在这样的部分中,您可以很好地有条件地定义一种弃用符号的方法。我的喜好通常是定义“警告”宏,因为大多数工具链都支持自定义编译器警告。然后,您可以继续使用特定的警告宏进行弃用等操作。对于支持专用弃用方法的平台,您可以使用它代替警告。


1

对于Intel Compiler v19.0,将其用作__INTEL_COMPILER评估1900

#  if defined(__INTEL_COMPILER)
#    define DEPRECATED [[deprecated]]
#  endif

适用于以下语言级别:

  • C ++ 17支持(/ Qstd = c ++ 17)
  • C ++ 14支持(/ Qstd = c ++ 14)
  • C ++ 11支持(/ Qstd = c ++ 11)
  • C11支持(/ Qstd = c11)
  • C99支持(/ Qstd = c99)

英特尔编译器存在一个似乎有错误的地方,即它不支持[[deprecated]]所有其他编译器都支持的某些语言元素的属性。例如,使用Intel Compiler v19.0编译GitHub上{fmtlib / fmt}库(非常出色)的v6.0.0。会破裂的。然后在GitHub commit中查看修复


这是不正确的。C ++属性在ICC上的C模式下不起作用。 实例__attribute__((deprecated)),OTOH至少可以追溯到ICC 13.0才能在C和C ++中工作,甚至可能还要远得多(英特尔倾向于不记录这种类型的东西,所以我不确定)。
nemequ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.