172

I have a method in a C++ interface that I want to deprecate, with portable code.

When I Googled for this all I got was a Microsoft specific solution; #pragma deprecated and __declspec(deprecated).

If a general or fully-portable deprecation solution is not available, I will accept as a "second prize solution" one that can be used multiple specific compilers, like MSVC and a GCC.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Diederik
  • 5,536
  • 3
  • 44
  • 60

7 Answers7

235

In C++14, you can mark a function as deprecated using the [[deprecated]] attribute (see section 7.6.5 [dcl.attr.deprecated]).

The attribute-token deprecated can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.

For example, the following function foo is deprecated:

[[deprecated]]
void foo(int);

It is possible to provide a message that describes why the name or entity was deprecated:

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

The message must be a string literal.

For further details, see “Marking as deprecated in C++14”.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
131

This should do the trick:

#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);

However, you will encounter problems if a function return type has a commas in its name e.g. std::pair<int, int> as this will be interpreted by the preprocesor as passing 2 arguments to the DEPRECATED macro. In that case you would have to typedef the return type.

Edit: simpler (but possibly less widely compatible) version here.

Community
  • 1
  • 1
Michael Platings
  • 3,045
  • 2
  • 25
  • 17
  • 8
    Instead of #error, it would be better to #define DEPRECATED(func) func – CesarB Nov 17 '08 at 10:41
  • @CesarB: I disagree; if there were no error, there would be no way to notice that something unexpected happened. – foraidt Nov 17 '08 at 11:12
  • 1
    mxp: The deprecation is only a warning, and hence I'd say that a warning that it isn't supported is all you need. – Leon Timmermans Nov 17 '08 at 15:45
  • 2
    Yep, I'd go for "#warning You need to implement DEPRECATED for this compiler", or some such. If that's impossible, then the porter can #define DEPRECATED(FUNC) FUNC, and live without it. – Steve Jessop Nov 17 '08 at 16:16
  • 2
    Unfortunately there's no standard way to output a compile warning in C++ :P #pragma message will have to do. – Michael Platings Nov 17 '08 at 18:04
  • 1
    Is it possible to mark a class Deprecated using this macro ? with something like DEPRECATED(Class()); ? – dzen May 06 '10 at 16:43
  • 4
    gcc's attribute syntax allows for the attribute to be in the same places as `__declspec(deprecated)` now, so the macro can be simplified. – bames53 Nov 29 '12 at 17:06
  • 1
    No need to pass argument to macros, just declare it as `#define DEPRECATED __declspec(deprecated)` and use as `DEPRECATED void MyApi()` – DarkWanderer Jan 20 '14 at 09:26
  • 1
    @bames53 & DarkWanderer I've added a new answer accordingly: http://stackoverflow.com/a/21265197/2651243. I thought it best not to change such a venerable answer just in case the new one breaks for older compilers. – Michael Platings Jan 21 '14 at 17:36
  • Can I and other people use your DEPRECATED macro in a commercial closed source application? – Vertexwahn Oct 06 '16 at 21:03
  • @Vertexwahn Sure! – Michael Platings Oct 11 '16 at 08:43
  • 1
    Note that this even works if you want to mark a 3rd party function deprecated, putting this statement after the include of a third party file makes it possible to mark some function deprectaed even outside of their header file. – jpo38 Dec 05 '17 at 07:35
  • So, shouldn't you delete this answer in favor of the simpler one? – einpoklum Feb 19 '23 at 19:31
68

Here's a simplified version of my 2008 answer:

#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);

See also:

Florian Castellane
  • 1,197
  • 2
  • 14
  • 38
Michael Platings
  • 3,045
  • 2
  • 25
  • 17
  • 20
    How do you `[[deprecate]]` your deprecated macros? :-) – graham.reeds Oct 13 '15 at 12:39
  • 4
    I can't see any significant difference between those two answers. Why did you post it a second time? – Tomáš Zato Nov 13 '15 at 14:29
  • 4
    You don't have to wrap it around the function so it's `DEPRECATED void foo(...);` instead of `DEPRECATED(void foo(...));` – dshepherd Jan 25 '16 at 17:25
  • 14
    You should have edited your 2008 answer rather than posting a new one. – Yakov Galka Jul 24 '16 at 13:38
  • 4
    This may not be as widely compatible as my other answer, hence I added this separately. – Michael Platings Oct 13 '16 at 09:04
  • 2
    If you want to be a bit more complete, you can also add the message, e.g. `DEPRECATED("Use bar instead") void foo(...);` – Johan Boulé Apr 20 '17 at 12:18
  • @graham.reeds `#pragma deprecated("DEPRECATED")` :) – Vizor Jun 12 '18 at 11:39
  • 2
    @graham.reeds, there isn't a way to use a C++ attribute *on* a macro, but if you just want to warn whenever the macro is invoked then in GCC 4.8+ as well as a few other compilers you can do `#define DEPRECATED _Pragma("GCC warning \"DEPRECATED is deprecated\"")`. MSVC also has a pragma: `#define DEPRECATED __pragma(message("DEPRECATED is deprecated"))`. If you're okay with informational messages instead of warnings you can get support from a few other compilers… take a look at [`HEDLEY_WARNING`](https://github.com/nemequ/hedley/blob/936b674230258626cac025b37d7af8eefc66b8df/hedley.h#L1776) – nemequ Mar 02 '20 at 19:20
  • @nemequ ["THAT'S HEDY!"](https://www.youtube.com/watch?v=vtf7SgIBwG0) – FeRD Mar 07 '21 at 17:08
  • 1
    @FeRD: [It's not "Hedy", it's "Hedley".](https://youtu.be/g2Bp8SqYrnE?t=92) ☺ – nemequ Mar 08 '21 at 22:09
23

In GCC you can declare your function with the attribute deprecated like this:

void myfunc() __attribute__ ((deprecated));

This will trigger a compile-time warning when that function is used in a .c file.

You can find more info under "Diagnostic pragmas" at http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html

bames53
  • 86,085
  • 15
  • 179
  • 244
Terje Mikal
  • 938
  • 6
  • 16
13

Here is a more complete answer for 2018.

These days, a lot of tools allow you to not just mark something as deprecated, but also provide a message. This allows you to tell people when something was deprecated, and maybe point them toward a replacement.

There is still a lot of variety in compiler support:

  • C++14 supports [[deprecated]]/[[deprecated(message)]].
  • __attribute__((deprecated)) is supported by GCC 4.0+ and ARM 4.1+
  • __attribute__((deprecated)) and __attribute__((deprecated(message))) is supported for:
    • GCC 4.5+
    • Several compilers which masquerade as GCC 4.5+ (by setting __GNUC__/__GNUC_MINOR__/__GNUC_PATCHLEVEL__)
    • Intel C/C++ Compiler going back to at least 16 (you can't trust __GNUC__/__GNUC_MINOR__, they just set it to whatever version of GCC is installed)
    • ARM 5.6+
  • MSVC supports __declspec(deprecated) since 13.10 (Visual Studio 2003)
  • MSVC supports __declspec(deprecated(message)) since 14.0 (Visual Studio 2005)

You can also use [[gnu::deprecated]] in recent versions of clang in C++11, based on __has_cpp_attribute(gnu::deprecated).

I have some macros in Hedley to handle all of this automatically which I keep up to date, but the current version (v2) looks like this:

#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

I'll leave it as an exercise to figure out how to get rid of the *_VERSION_CHECK and *_HAS_ATTRIBUTE macros if you don't want to use Hedley (I wrote Hedley largely so I wouldn't have to think about that on a regular basis).

If you use GLib, you can use the G_DEPRECATED and G_DEPRECATED_FOR macros. They're not as robust as the ones from Hedley, but if you already use GLib there is nothing to add.

nemequ
  • 16,623
  • 1
  • 43
  • 62
4

Dealing with portable projects it's almost inevitable that you at some point need a section of preprocessed alternatives for a range of platforms. #ifdef this #ifdef that and so on.

In such a section you could very well conditionally define a way to deprecate symbols. My preference is usually to define a "warning" macro since most toolchains support custom compiler warnings. Then you can go on with a specific warning macro for deprecation etc. For the platforms supporting dedicated deprecation methods you can use that instead of warnings.

sharkin
  • 12,162
  • 24
  • 86
  • 122
1

For Intel Compiler v19.0, use this as __INTEL_COMPILER evaluates to 1900:

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

Works for the following language levels:

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

The Intel Compiler has what appears a bug in that it does not support the [[deprecated]] attribute on certain language elements that all other compilers do. For an example, compile v6.0.0 of the (remarkly superb) {fmtlib/fmt} library on GitHub with Intel Compiler v19.0. It will break. Then see the fix in the GitHub commit.

Contango
  • 76,540
  • 58
  • 260
  • 305
  • This is incorrect; C++ attributes do not work in C mode on ICC. [Example](https://godbolt.org/z/JVJBwZ). `__attribute__((deprecated))`, OTOH, works in C and C++ going back to at least ICC 13.0, probably much further (Intel tends not to document this type of stuff so I can't be sure). – nemequ Mar 02 '20 at 19:07