C++ mark as deprecated
C++C++ Problem Overview
I have a method in an interface that I want to deprecate with portable C++.
When I Googled for this all I got was a Microsoft specific solution; #pragma deprecated
and __declspec(deprecated)
.
A second prize solution would be to ifdef
a MSVC and a GCC solution.
C++ Solutions
Solution 1 - C++
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”.
Solution 2 - C++
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.
Solution 3 - C++
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:
Solution 4 - C++
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
Solution 5 - C++
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.
Solution 6 - C++
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.
Solution 7 - C++
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.