{"id":109570,"date":"2024-03-25T07:00:00","date_gmt":"2024-03-25T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109570"},"modified":"2024-03-25T08:55:50","modified_gmt":"2024-03-25T15:55:50","slug":"20240325-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240325-00\/?p=109570","title":{"rendered":"Why isn&#8217;t C++ using my default parameter to deduce a template type?"},"content":{"rendered":"<p>Consider the following function:<\/p>\n<pre>template&lt;typename T&gt;\r\nvoid Increment(T value = 1);\r\n<\/pre>\n<p>If you call it with no arguments, C++ cannot deduce the template type parameter:<\/p>\n<pre style=\"white-space: pre-wrap;\">\/\/ clang\r\nerror: no matching function for call to 'Increment'\r\ncouldn't infer template argument 'T'\r\n\r\n\/\/ gcc\r\nerror: no matching function for call to 'Increment()'\r\ncouldn't deduce template parameter 'T'\r\n\r\n\/\/ msvc\r\nerror C2672: 'Increment': no matching overload function found\r\ncould not deduce template argument for 'T'\r\n<\/pre>\n<p>&#8220;What do you mean, you can&#8217;t deduce the template argument? It&#8217;s right there: The default parameter is <code>1<\/code>, so <code>T<\/code> should be <code>int<\/code>!&#8221;<\/p>\n<p>The catch is that C++ does not consider default parameters when performing template deduction. It performs deduction only with explicitly-provided parameters.<\/p>\n<p>A very common pattern is for the default value of a function parameter to be dependent upon a template type parameter.<\/p>\n<pre>template&lt;typename T&gt;\r\nvoid SetSize(size_t N, T value <span style=\"border: solid 1px currentcolor;\">= T{}<\/span>);\r\n<\/pre>\n<p>The intention here is that if you call <code>SetSize<\/code> and don&#8217;t provide a value, we will use a default-constructed value. You see this pattern, for example, in <code>std::vector::resize()<\/code>.<\/p>\n<p>If default parameters were used by type inference, then you&#8217;d have a circular dependency:\u00b9 To figure out what <code>T<\/code> is, you need to know the default parameter, but to know the default parameter, you need to know what <code>T<\/code> is.\u00b2<\/p>\n<p>But all is not lost. If you want to provide a default type for <code>T<\/code>, you can provided it as part of the template type parameter list:<\/p>\n<pre>template&lt;typename T <span style=\"border: solid 1px currentcolor;\">= int<\/span>&gt;\r\nvoid Increment(T value = 1);\r\n<\/pre>\n<p>If you call <code>Increment()<\/code> with no parameters, the compiler cannot deduce <code>T<\/code> from the actual parameters (since there are none), so it uses the default type in the template type parameter list, and you get <code>int<\/code>. Once that&#8217;s decided, the default parameter is then implicitly converted from <code>1<\/code>.<\/p>\n<p>\u00b9 I wouldn&#8217;t be surprised if there turns out to be a circular dependency with overload resolution, but I am too tired to try to work out the details.<\/p>\n<p>\u00b2 You might say, &#8220;Sure, that general case doesn&#8217;t work, but certainly you can make it work in this case!&#8221; There is a trade-off when you add rules to handle special cases. The good part is that more cases work. The bad part is that you now have more rules. Often, it&#8217;s better to have a simple set of easily-understood and easily-remembered rules, even if they don&#8217;t cover all possible cases.\u00b3<\/p>\n<p>\u00b3 One might argue that the C++ committee had already abandoned the principle of &#8220;fewer rules that are easier to remember&#8221; a long time ago. For example, <a title=\"Down with typename!\" href=\"https:\/\/wg21.link\/p0634r3\"> C++20 made <code>typename<\/code> optional in a half dozen special cases<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trying to have it both ways.<\/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-109570","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Trying to have it both ways.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109570","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=109570"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109570\/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=109570"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109570"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109570"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}