Deprecating functions and methods in C++
Refactoring a C++ code base for a binary API, I needed to deprecate some functions and communicate changes to API users. While noted in the API’s documentation, people don’t read documentation, so I wanted the compiler to warn users as well (not that people read compiler warnings either!).
C++14 has a [[deprecated]] attribute, but what if you want to use that if supported, and do something else for other compilers?
Macros to the rescue! Below will use the canonical C++14 way if supported, and an equivalent proprietary method for GCC and Microsoft Visual C++ respectively.
// Helper to deprecate functions and methods // See https://blog.samat.io/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/ // For C++14 #if __cplusplus >= 201402L #if defined(__has_cpp_attribute) #if __has_cpp_attribute(deprecated) #define DEPRECATED(msg, func) [[deprecated(msg)]] func #endif #endif // For everyone else #else #ifdef __GNUC__ #define DEPRECATED(msg, func) func __attribute__ ((deprecated(msg))) #elif defined(_MSC_VER) #define DEPRECATED(msg, func) __declspec(deprecated(msg)) func #endif #endif
To use it: in your header file for you API, simply wrap a function or method declaration with the macro. From:
void go(size_t goRadius, float one, float two, float three);
wrap it like so:
DEPRECATED("Use goNew()", void go(size_t goRadius, float one, float two, float three));
And you’ll get a warning. Here’s what it looks like with GCC 6.2:
/api.cpp: In member function ‘void SomeClass::go()’: /api.cpp:104:23: warning: ‘void SomeClass::go(size_t, float, float, float)’ is deprecated: Use goNew() [-Wdeprecated-declarations] go(10, 1, 1, 1); ^ In file included from /api.cpp:17:0: /api.h:135:37: note: declared here DEPRECATED("Use goNew()", void go(size_t goRadius, float one, float two, float three)); ^ /api.h:41:63: note: in definition of macro ‘DEPRECATED’ #define DEPRECATED(msg, func) [[deprecated(msg)]] func ^~~~
The macro is not perfect, however (or rather, compilers are not).
The canonical way for checking if[[deprecated]]is supported is with the compiler definition__has_cpp_attribute(deprecated); unfortunately, GCC 6.2 defines this symbol regardless of whether you are in C++14 mode or not. And then it prints a warning when run in-pedanticmode, even though it’s supported!
In the above snippet, the C++14 method is only used if the compiler fully supports C++14 and is in C++14 mode. If that’s not important to you, consider removing that extra if statement, and use this instead:
// Helper to deprecate functions and methods // See https://blog.samat.io/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/ // For C++14 #if defined(__has_cpp_attribute) #if __has_cpp_attribute(deprecated) #define DEPRECATED(msg, func) [[deprecated(msg)]] func #endif // For everyone else #else #ifdef __GNUC__ #define DEPRECATED(msg, func) func __attribute__ ((deprecated(msg))) #elif defined(_MSC_VER) #define DEPRECATED(msg, func) __declspec(deprecated(msg)) func #endif #endif