{"id":103669,"date":"2020-04-13T07:00:00","date_gmt":"2020-04-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103669"},"modified":"2020-04-12T20:51:28","modified_gmt":"2020-04-13T03:51:28","slug":"20200413-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200413-00\/?p=103669","title":{"rendered":"The type-dependent type or value that is independent of the type"},"content":{"rendered":"<p>Some time ago, we saw how to <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200319-00\/?p=103572\"> create a type-dependent expression that is always false<\/a>. I noted that it feels weird creating a whole new type just to create a fixed <code>false<\/code> value.<\/p>\n<p>But maybe we can make it more useful by generalizing it.<\/p>\n<pre>template&lt;typename T, typename...&gt;\r\nusing unconditional_t = T;\r\n\r\ntemplate&lt;typename T, T v, typename...&gt;\r\ninline constexpr T unconditional_v = v;\r\n<\/pre>\n<p>The <code>unconditional_t<\/code> alias template always represents the type <code>T<\/code>, and the <code>unconditional_v<\/code> variable template always represents the value <code>v<\/code>.<\/p>\n<pre>template&lt;typename Whatever&gt;\r\nvoid f()\r\n{\r\n  \/\/ X is always int\r\n  using X = unconditional_t&lt;int, Whatever&gt;;\r\n\r\n  \/\/ v is always 42\r\n  auto v = unconditional_v&lt;int, 42, Whatever&gt;;\r\n}\r\n<\/pre>\n<p>Even though the resulting type or value is always the same, it is nevertheless a dependent type, and therefore the evaluation does not occur until template instantiation.<\/p>\n<p>We can use this to solve our &#8220;cannot <code>static_assert(false)<\/code> in a discarded statement&#8221; problem:<\/p>\n<pre>auto lambda = [<span style=\"opacity: .5;\">total<\/span>](auto op, auto value) mutable\r\n{\r\n  <span style=\"opacity: .5;\">using Op = decltype(op);<\/span>\r\n  <b>if constexpr<\/b> (<span style=\"opacity: .5;\">std::is_same_v&lt;Op, add_tax_t&gt;<\/span>) {\r\n   <span style=\"opacity: .5;\">total += total * value; \/\/ value is the tax rate\r\n   return total;<\/span>\r\n  } <b>else if constexpr<\/b> (<span style=\"opacity: .5;\">std::is_same_v&lt;Op, apply_discount_t&gt;<\/span>) {\r\n   <span style=\"opacity: .5;\">total -= std::max(value, total); \/\/ value is the discount\r\n   return total;<\/span>\r\n  } <b>else<\/b> {\r\n   <b>static_assert(unconditional_v&lt;Op, bool, false&gt;,<\/b>\r\n                \"Don't know what you are asking me to do.\");\r\n  }\r\n};\r\n<\/pre>\n<p>The <code>unconditional_t<\/code> generalizes the alias template <code>std::void_t&lt;...&gt;<\/code>: Whereas <code>std::void_t&lt;...&gt;<\/code> always evaluates to <code>void<\/code>, the <code>unconditional_t<\/code> lets you pick the type that it resolves to.<\/p>\n<pre>template&lt;typename... Types&gt;\r\nusing void_t = unconditional_t&lt;void, Types...&gt;;\r\n<\/pre>\n<p>The <code>unconditional_t<\/code> also generalizes the template class <code>std::type_identity&lt;T&gt;<\/code>: Whereas <code>std::type_identity&lt;T&gt;<\/code> takes only one template type parameter, the <code>unconditional_t<\/code> lets you pass extra parameters, which are evaluated (for SFINAE) but otherwise ignored.<\/p>\n<pre>template&lt;typename T&gt;\r\nusing type_identity = unconditional_t&lt;T&gt;;\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>To delay the evaluation until instantiation.<\/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-103669","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>To delay the evaluation until instantiation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103669","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=103669"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103669\/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=103669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}