{"id":103986,"date":"2020-07-16T07:00:00","date_gmt":"2020-07-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103986"},"modified":"2020-07-16T07:53:54","modified_gmt":"2020-07-16T14:53:54","slug":"20200716-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200716-00\/?p=103986","title":{"rendered":"Deconstructing function pointers in a C++ template, the calling convention conundrum"},"content":{"rendered":"<p>We continue <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200715-00\/?p=103984\"> our attempt to build a traits class for function pointers<\/a> by incorporating another attribute of function pointers: The calling convention.<\/p>\n<p>Calling conventions are not formally part of the standard, but they are a common extension, supported by the Microsoft compiler, gcc, clang, and icc. (Possibly others; I didn&#8217;t research it too deeply.)<\/p>\n<p>None of the compilers can deduce the calling convention, so we&#8217;ll have to write things out multiple times, just like we did for <code>noexcept<\/code>.<\/p>\n<p>Let&#8217;s start by defining our own macros for calling conventions, since the compilers express them differently. And for simplicity, let&#8217;s start with just two of the available calling conventions: <code>cdecl<\/code> and <code>stdcall<\/code>. There are also <code>fastcall<\/code> and <code>vectorcall<\/code>, but we&#8217;ll deal with those analogously.<\/p>\n<pre>#if defined(__GNUC__) || defined(__clang__)\r\n  #define CC_CDECL __attribute__((cdecl))\r\n  #define CC_STDCALL __attribute__((stdcall))\r\n#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)\r\n  #define CC_CDECL __cdecl\r\n  #define CC_STDCALL __stdcall\r\n#else\r\n  #define CC_CDECL\r\n  #define CC_STDCALL\r\n#endif\r\n<\/pre>\n<p>The order of the tests is significant because the Intel compiler sets both <code>__INTEL_COMPILER<\/code> and <code>__GNUC__<\/code> when running in gcc mode, and in that case, we want to use the gcc-style attributes.<\/p>\n<p>I&#8217;ll also create a type for each calling convention. I&#8217;ll have each calling convention be represented by a pointer to a simple function that uses the indicated calling convention. This&#8217;ll come in handy later.<\/p>\n<pre>struct CallingConventions\r\n{\r\n    using Cdecl = void(CC_CDECL*)();\r\n    using Stdcall = void(CC_STDCALL*)();\r\n};\r\n<\/pre>\n<p>And now to create all the partial specializations. We have two calling conventions, times two <code>noexcept<\/code> flavors, times two variadic-ness-es, for a total of eight partial specializations. This is starting to get annoying, especially since there are plenty more calling conventions to come. But we&#8217;re still trying to figure out what we&#8217;re doing, so let&#8217;s look just at the case of a non-variadic non-<code>noexcept<\/code> function, in varying calling conventions.<\/p>\n<pre>template&lt;typename R, typename... Args&gt;\r\nstruct FunctionTraits&lt;R(CC_CDECL*)(Args...)&gt;\r\n    : FunctionTraitsBase&lt;R, Args...&gt;\r\n{\r\n  using Pointer = R(CC_CDECL*)(Args...);\r\n  using CallingConvention = CallingConventions::Cdecl;\r\n};\r\n\r\ntemplate&lt;typename R, typename... Args&gt;\r\nstruct FunctionTraits&lt;R(CC_STDCALL*)(Args...)&gt;\r\n    : FunctionTraitsBase&lt;R, Args...&gt;\r\n{\r\n  using Pointer = R(CC_STDCALL*)(Args...);\r\n  using CallingConvention = CallingConventions::Stdcall;\r\n};\r\n<\/pre>\n<p>That wasn&#8217;t so hard, albeit repetitive. (Especially when we add the other three variations.) Now we can deduce the calling convention from a function pointer.<\/p>\n<p>Well, except that this fails to compile on architectures where some of the calling conventions end up the same. For example, even though the four calling conventions are distinct on x86-32, they all collapse into one calling convention on x86-64. If you compile the above code on x86-64, you get errors because the compiler sees duplicate definitions.<\/p>\n<p>Fixing this will require quite a bit more work, which we&#8217;ll look at next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Teasing out the calling convention from a function pointer.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103986","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Teasing out the calling convention from a function pointer.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103986","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103986"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103986\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103986"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103986"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103986"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}