<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Samat Says (Posts about C++)</title><link>https://blog.samat.org/</link><description></description><atom:link href="https://blog.samat.org/tag/c%2B%2B.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Fri, 29 Jun 2018 09:25:27 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Deprecating functions and methods in C++</title><link>https://blog.samat.org/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/</link><dc:creator>Samat K Jain</dc:creator><description>&lt;div&gt;&lt;p&gt;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!).&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html"&gt;C++14 has a [[deprecated]] attribute&lt;/a&gt;, but what if you want to use that if supported, and do something else for other compilers?&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;pre class="code text"&gt;&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-1"&gt;&lt;/a&gt;// Helper to deprecate functions and methods
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-2"&gt;&lt;/a&gt;// See https://blog.samat.io/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-3"&gt;&lt;/a&gt;// For C++14
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-4"&gt;&lt;/a&gt;#if __cplusplus &amp;gt;= 201402L
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-5"&gt;&lt;/a&gt;    #if defined(__has_cpp_attribute)
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-6"&gt;&lt;/a&gt;        #if __has_cpp_attribute(deprecated)
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-7"&gt;&lt;/a&gt;            #define DEPRECATED(msg, func) [[deprecated(msg)]] func
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-8"&gt;&lt;/a&gt;        #endif
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-9"&gt;&lt;/a&gt;    #endif
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-10"&gt;&lt;/a&gt;// For everyone else
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-11"&gt;&lt;/a&gt;#else
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-12"&gt;&lt;/a&gt;    #ifdef __GNUC__
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-13"&gt;&lt;/a&gt;        #define DEPRECATED(msg, func) func __attribute__ ((deprecated(msg)))
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-14"&gt;&lt;/a&gt;    #elif defined(_MSC_VER)
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-15"&gt;&lt;/a&gt;        #define DEPRECATED(msg, func) __declspec(deprecated(msg)) func
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-16"&gt;&lt;/a&gt;    #endif
&lt;a name="rest_code_c351d23e9ad04dfea0e052a0b7c738a3-17"&gt;&lt;/a&gt;#endif
&lt;/pre&gt;&lt;p&gt;To use it: in your header file for you API, simply wrap a function or method declaration with the macro. From:&lt;/p&gt;
&lt;pre class="code c++"&gt;&lt;a name="rest_code_30c4e1761b2e4bf6a545dcf719082d8e-1"&gt;&lt;/a&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;goRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;wrap it like so:&lt;/p&gt;
&lt;pre class="code c++"&gt;&lt;a name="rest_code_0cf2409ced7a473aa34c78fc5a2cc65e-1"&gt;&lt;/a&gt;&lt;span class="n"&gt;DEPRECATED&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Use goNew()"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;goRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;And you'll get a warning. Here's what it looks like with GCC 6.2:&lt;/p&gt;
&lt;pre class="code text"&gt;&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-1"&gt;&lt;/a&gt;/api.cpp: In member function ‘void SomeClass::go()’:
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-2"&gt;&lt;/a&gt;/api.cpp:104:23: warning: ‘void SomeClass::go(size_t, float, float, float)’ is deprecated: Use goNew() [-Wdeprecated-declarations]
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-3"&gt;&lt;/a&gt;     go(10, 1, 1, 1);
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-4"&gt;&lt;/a&gt;                   ^
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-5"&gt;&lt;/a&gt;In file included from /api.cpp:17:0:
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-6"&gt;&lt;/a&gt;/api.h:135:37: note: declared here
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-7"&gt;&lt;/a&gt;     DEPRECATED("Use goNew()", void go(size_t goRadius, float one, float two, float three));
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-8"&gt;&lt;/a&gt;                                    ^
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-9"&gt;&lt;/a&gt;/api.h:41:63: note: in definition of macro ‘DEPRECATED’
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-10"&gt;&lt;/a&gt;             #define DEPRECATED(msg, func) [[deprecated(msg)]] func
&lt;a name="rest_code_723ede9bf13843dfadffe6b2a928284c-11"&gt;&lt;/a&gt;                                                           ^~~~
&lt;/pre&gt;&lt;p&gt;The macro is not perfect, however (or rather, compilers are not).&lt;/p&gt;
&lt;p&gt;The canonical way for checking if &lt;tt class="docutils literal"&gt;[[deprecated]]&lt;/tt&gt; is supported is with the compiler definition &lt;tt class="docutils literal"&gt;__has_cpp_attribute(deprecated)&lt;/tt&gt;;
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 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-pedantic&lt;/span&gt;&lt;/tt&gt; mode, even though it's supported!&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;pre class="code text"&gt;&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-1"&gt;&lt;/a&gt;// Helper to deprecate functions and methods
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-2"&gt;&lt;/a&gt;// See https://blog.samat.io/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-3"&gt;&lt;/a&gt;// For C++14
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-4"&gt;&lt;/a&gt;#if defined(__has_cpp_attribute)
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-5"&gt;&lt;/a&gt;    #if __has_cpp_attribute(deprecated)
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-6"&gt;&lt;/a&gt;        #define DEPRECATED(msg, func) [[deprecated(msg)]] func
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-7"&gt;&lt;/a&gt;    #endif
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-8"&gt;&lt;/a&gt;// For everyone else
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-9"&gt;&lt;/a&gt;#else
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-10"&gt;&lt;/a&gt;    #ifdef __GNUC__
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-11"&gt;&lt;/a&gt;        #define DEPRECATED(msg, func) func __attribute__ ((deprecated(msg)))
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-12"&gt;&lt;/a&gt;    #elif defined(_MSC_VER)
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-13"&gt;&lt;/a&gt;        #define DEPRECATED(msg, func) __declspec(deprecated(msg)) func
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-14"&gt;&lt;/a&gt;    #endif
&lt;a name="rest_code_cee5cb2aafe44483a53c7aaab9fc237c-15"&gt;&lt;/a&gt;#endif
&lt;/pre&gt;&lt;/div&gt;</description><category>C++</category><category>C++14</category><category>Programming</category><guid>https://blog.samat.org/2017/02/27/Deprecating-functions-and-methods-in-Cplusplus/</guid><pubDate>Mon, 27 Feb 2017 00:00:00 GMT</pubDate></item></channel></rss>