{"id":103553,"date":"2020-03-11T07:00:00","date_gmt":"2020-03-11T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103553"},"modified":"2020-03-10T18:43:59","modified_gmt":"2020-03-11T01:43:59","slug":"20200311-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200311-00\/?p=103553","title":{"rendered":"How can I create a type-dependent expression that is always false?"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191107-00\/?p=103071\"> Giving a C++ lambda expression more than one <code>operator()<\/code><\/a> was an abuse of the language.\u00b9 But one of the side effects of exploring ways to abuse the language is that during your explorations, you may <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190711-00\/?p=102682\"> discover a useful trick<\/a>.<\/p>\n<p>One of the things I had to do was prevent compilation from succeeding if the lambda was called incorrectly. I had a chain of <code>if constexpr<\/code> tests for the valid cases, and I needed to put a <code>static_assert<\/code> in the <code>else<\/code> that said &#8220;You should never get here.&#8221;<\/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;\"><span style=\"text-decoration: line-through;\">total += total * value; \/\/ value is the tax rate<\/span>\r\n   <span style=\"text-decoration: line-through;\">return total;<\/span><\/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;\"><span style=\"text-decoration: line-through;\">total -= std::max(value, total); \/\/ value is the discount<\/span>\r\n   <span style=\"text-decoration: line-through;\">return total;<\/span><\/span>\r\n  } <b>else<\/b> {\r\n   <b>static_assert(false,<\/b> \"Don't know what you are asking me to do.\");\r\n  }\r\n};\r\n<\/pre>\n<p>However, this does not compile because the <code>static_<code><\/code>assert<\/code> fails immediately.<\/p>\n<p>The reason is that the controlling expression for the <code>static_<code><\/code>assert<\/code> is not dependent upon the type of the arguments, and therefore it is evaluated when the lambda is compiled, not when the lambda is invoked (and the implicit template instantiated).\u00b2<\/p>\n<p>In order to defer the <code>static_<code><\/code>assert<\/code> to instantiation, we need to make it type-dependent.<\/p>\n<p>What is a type-dependent expression that is always false?<\/p>\n<p>We could always make up our own:<\/p>\n<pre>template&lt;typename T&gt;\r\ninline constexpr bool always_false_v = false;\r\n\r\n...\r\n\r\n static_assert(<span style=\"color: blue;\">always_false_v&lt;Op&gt;<\/span>,\r\n               \"Don't know what you are asking me to do.\");\r\n<\/pre>\n<p>but it feels weird creating a whole new variable template just to generate a fixed <code>false<\/code> value.\u00b3 Maybe we can live off the land.<\/p>\n<p>We could take advantage of the fact that <code>sizeof<\/code> is never zero.\u2074<\/p>\n<pre> static_assert(<span style=\"color: blue;\">!sizeof(Op)<\/span>,\r\n               \"Don't know what you are asking me to do.\");\r\n<\/pre>\n<p>but this runs into problems if <code>Op<\/code> is an incomplete type or <code>void<\/code>. Now, the way we happen to have written our code, an incomplete type and <code>void<\/code> are not possible because the type corresponds to an actual parameter. But let&#8217;s look for a more general solution.<\/p>\n<p>If the type is indeed incomplete or <code>void<\/code>, then the code will fail to compile, but the error message will be confusing because the provided error text will not be used: The error occurred before the compiler could get that far.<\/p>\n<p>However, <i>pointers to<\/i> incomplete types or <code>void<\/code> are valid. So we could do this:<\/p>\n<pre> static_assert(<span style=\"color: blue;\">!sizeof(Op*)<\/span>,\r\n               \"Don't know what you are asking me to do.\");\r\n<\/pre>\n<p>A static assertion of a type-dependent expression that is always false is a handy thing to put into templates, because it defers the assertion failure to the instantiation of the template. Here, we used it in a potentially-discarded statement, so that the instantiation does not occur when the statement is discarded.<\/p>\n<p>We&#8217;ll find another use next time.<\/p>\n<p><b>Bonus chatter<\/b>: <a href=\"https:\/\/twitter.com\/MalwareMinigun\"> Billy O&#8217;Neal<\/a> called out some gotchas with this approach, which I&#8217;ll take up in a future entry.<\/p>\n<p>\u00b9 What some people call an abuse of the language others call a <i>proxy object<\/i>, such as the one produced by <code>std::vector&lt;bool&gt;<\/code>&#8216;s <code>[]<\/code> operator.<\/p>\n<p>\u00b2 This does raise a confusing point in the C++ standard. According to the standard, the not-used branch of an <code>if constexpr<\/code> is a <i>discarded statement<\/i>. This is the only place where the term <i>discarded statement<\/i> appears in the standard. And it is never defined! The closest thing to a definition is the sentence<\/p>\n<blockquote class=\"q\"><p>During the instantiation of an enclosing templated entity (Clause 17), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.<\/p><\/blockquote>\n<p>which describes a <i>discarded <u>sub<\/u>statement<\/i>. And it doesn&#8217;t really define what a discarded substatement is. It just names one characteristic of discarded substatements.<\/p>\n<p>I think the standard intended the sentence to be something like<\/p>\n<blockquote class=\"q\"><p><u>A <i>discarded statement<\/i> is treated the same as a statement, except that<\/u> during the instantiation of an enclosing templated entity (Clause 17), if the condition is not value-dependent after its instantiation, the discarded statement (if any) is not instantiated.<\/p><\/blockquote>\n<p>\u00b3 See <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2019\/p1830r1.pdf\"> the proposal for <code>std::dependent_<\/code><code>false<\/code><\/a> (and <a href=\"https:\/\/github.com\/cplusplus\/papers\/issues\/572\"> committee sentiment<\/a>) for further discussion.<\/p>\n<p>\u2074 <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/ebo\"> Empty base optimization<\/a> and <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/attributes\/no_unique_address\"> <code>[[no_<code><\/code>unique_<code><\/code>address]]<\/code><\/a> also scare me, because they can lead to an object having an effective size of zero. I don&#8217;t want to get caught out if a future version of the standard makes some subtle changes that lead to <code>sizeof(T) == 0<\/code> in some fringe cases.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use information that you know to be true (or false).<\/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-103553","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Use information that you know to be true (or false).<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103553","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=103553"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103553\/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=103553"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103553"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}