{"id":1685,"date":"2022-08-29T02:00:00","date_gmt":"2022-08-29T08:00:00","guid":{"rendered":"https:\/\/www.elbeno.com\/blog\/?p=1685"},"modified":"2022-08-29T10:29:51","modified_gmt":"2022-08-29T16:29:51","slug":"constexpr-function-parameters","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1685","title":{"rendered":"constexpr Function Parameters"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">The Set-up<\/h2>\n\n\n\n<p>In C++, this doesn&#8217;t work:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>consteval auto square(int x) -&gt; int { return x * x; }\n\nconstexpr auto twice_square(int x) -&gt; int { return square(x); }<\/code><\/pre>\n\n\n\n<p>The compiler complains, quite rightly:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>error: call to consteval function 'square' is not a constant expression\n\nnote: function parameter 'x' with unknown value cannot be used in a constant expression<\/code><\/pre>\n\n\n\n<p>Despite the fact that twice_square is a <code>constexpr<\/code> function, its parameter <code>x<\/code> is <em>not<\/em> <code>constexpr<\/code>. We can&#8217;t use it in a <code>static_assert<\/code>, we can&#8217;t pass it to a template, we can&#8217;t call an immediate (<code>consteval<\/code>) function with it.<\/p>\n\n\n\n<p>So far, so well known. This is the current situation in C++, although this area is a potential future expansion of <code>constexpr<\/code> (see <a href=\"https:\/\/wg21.link\/p1045\">P1045<\/a>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Hook<\/h2>\n\n\n\n<p>And yet&#8230; we all know that C++ has some dark corners.<\/p>\n\n\n\n<p>A disclaimer is in order. I don&#8217;t know why the technique I&#8217;m about to cover works, and I haven&#8217;t found the part of the standard that guarantees it (or not). So the possibilities lie on a spectrum:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>This is a valid technique, and it&#8217;s explicitly called out in the standard<br>somewhere.<\/li><li>This is a valid technique that&#8217;s a consequence of a valid reading of perhaps several parts of the standard, but not explicitly called out.<\/li><li>This is known to the standard and left up to implementations, who happen to mostly make the same choice.<\/li><li>This is outside the standard, but a logical consequence of how C++ must be implemented, so implementations are bound to make the same choice.<\/li><li>This is behaviour that is prohibited by the standard.<\/li><li>This is behaviour for which the standard imposes no requirements.<\/li><\/ol>\n\n\n\n<p>Things in buckets 1, 2 and 3 are well known. Stateful template metaprogramming is an example of something in bucket 4, that the committee would like to move into bucket 5. And bucket 6 is of course undefined behaviour.<\/p>\n\n\n\n<p>My gut feeling is that we are somewhere in 2-3 territory here. The technique I&#8217;m about to highlight is accepted by Clang, GCC and MSVC, and the basics work in every standard since C++11. So 5 seems unlikely. But I could well be wrong &#8212; <em>caveat lector<\/em>. And let&#8217;s get to it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Tale<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>The most exciting phrase to hear in science, the one that heralds new discoveries, is not \u201cEureka\u201d but \u201cThat\u2019s funny\u2026\u201d<\/p><cite>Isaac Asimov (1920\u20131992)<\/cite><\/blockquote>\n\n\n\n<p>My suspicions were first aroused while reading a code review recently. The engineer who&#8217;d written the code at the time perhaps didn&#8217;t appreciate the implication of what they&#8217;d written.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>template &lt;auto F&gt;\nconcept C = true;\n\nauto do_something(auto fn) {\n  static_assert(C&lt;fn()&gt;);\n}\n\ndo_something(&#91;]{});<\/code><\/pre>\n\n\n\n<p>The actual code is removed to highlight the structure. We&#8217;re passing a lambda expression into a function template. And then we&#8217;re verifying that the result of calling the lambda satisfies a concept. And by the way, if it&#8217;s new to you that concepts can work on NTTPs, that&#8217;s also a thing &#8212; although it&#8217;s not well supported by so-called &#8220;terse syntax&#8221;.<\/p>\n\n\n\n<p>But hold on here, <code>fn<\/code> is a function parameter. And function parameters aren&#8217;t <code>constexpr<\/code>! So why is the <code>static_assert<\/code> well-formed?<\/p>\n\n\n\n<p>Since C++17, the function call operators of lambda expressions are implicitly <code>constexpr<\/code>. But they aren&#8217;t <code>static<\/code> (yet &#8212; see <a href=\"https:\/\/wg21.link\/P1169\">P1169<\/a>), so there is an implicit object parameter here that should not be a constant expression &#8211; except that the compiler thinks that it is? Again, I&#8217;m not sure quite yet what is happening here.<\/p>\n\n\n\n<p>A bit of experimentation shows that this works for lambdas that don&#8217;t capture. And for empty structs with function call operators. And for any kind of derived structure, as long as it is empty, including overload sets deriving from several lambda expressions in the familiar way.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>template &lt;typename... Ts&gt; \nstruct overloaded : Ts... { \n  using Ts::operator()...;\n};<\/code><\/pre>\n\n\n\n<p>And on the MSVC compiler with support for <a href=\"https:\/\/wg21.link\/P0847\">P0847<\/a>, it also works with explicit object parameters.<\/p>\n\n\n\n<p>So to achieve &#8220;<code>constexpr<\/code> function parameters&#8221; it seems wrapping values inside non-capturing lambda expressions and then calling to unwrap in a <code>constexpr<\/code> context is possible. And in fact, this is the technique used by Jason Turner in <a href=\"https:\/\/www.youtube.com\/watch?v=ABg4_EV5L3w\">C++ Weekly Episode 313<\/a>, &#8220;The <code>constexpr<\/code> problem that took me 5 years to fix!&#8221;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Wire<\/h2>\n\n\n\n<p>That on its own is strange. But then I had another idea.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>#define constexpr_value(X) \\\n&#91;] { \\\n  struct { \\\n    consteval operator decltype(X)() const noexcept { \\\n      return X; \\\n    } \\\n    using constexpr_value_t = void; \\\n  } val; \\\n  return val; \\\n}()<\/code><\/pre>\n\n\n\n<p>What if I wrap up a value inside an empty structure with a compile-time conversion operator? The immediately-invoked lambda expression on the outside here is just to turn the whole thing into an expression. And the alias declaration is doing basically the same job as <code>is_transparent<\/code> in the standard library: it allows us to detect compile-time values with a concept.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>template &lt;typename T, typename U&gt;\nconcept compile_time = \n  requires { typename T::constexpr_value_t; } \n  and std::convertible_to&lt;T, U&gt;;<\/code><\/pre>\n\n\n\n<p>Now I can write the following:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>consteval auto square(int x) -&gt; int { return x * x; }\n\nconstexpr auto twice_square(compile_time&lt;int&gt; auto x) -&gt; int {\n  return square(x);\n}<\/code><\/pre>\n\n\n\n<p>and call it:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>twice_square(constexpr_value(4));<\/code><\/pre>\n\n\n\n<p>And everything is happy. In fact, <code>twice_square<\/code> doesn&#8217;t even have to be a <code>constexpr<\/code> function: the entire &#8220;<code>constexpr<\/code>-ness&#8221; is contained within <code>constexpr_value<\/code>. And the result of <code>constexpr_value<\/code> doesn&#8217;t even need to be assigned to a <code>constexpr<\/code> variable; this works just the same saying:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>auto x = constexpr_value(4);\ntwice_square(x);<\/code><\/pre>\n\n\n\n<p>Regular non-<code>constexpr<\/code> functions can take arguments like this as use them in arbitrary <code>constexpr<\/code> contexts as needed, e.g.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>auto sqrt(compile_time&lt;double&gt; x) -&gt; double {\n  static_assert(x &gt;= 0, \"negative numbers not allowed\");\n  return std::sqrt(x);\n}<\/code><\/pre>\n\n\n\n<p>When I call this with a cromulent <code>constexpr_value<\/code>, all the compile-time machinery melts away and it&#8217;s a regular call to <code>std::sqrt<\/code>. When I call it with a negative <code>constexpr_value<\/code>, the <code>static_assert<\/code> fires. Contrast this with a <code>throw<\/code> inside an <code>if consteval<\/code> block or something similar that we&#8217;d typically use in a <code>constexpr<\/code> function today to signal an error at compile time: I think this is clearer and gives a nicer error.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Shut-out<\/h2>\n\n\n\n<p>This works on all 3 major compilers, and the fundamentals work all the way back to C++11. I have noticed that the compilers differ slightly when using a <code>constexpr_value<\/code> as a NTTP, seemingly dependent on where the conversion happens. For example there is difference between:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>template &lt;auto N&gt;\nconstexpr int var = N;<\/code><\/pre>\n\n\n\n<p>and<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#c8f8ff\"><code>template &lt;int N&gt;\nconstexpr auto var = N;<\/code><\/pre>\n\n\n\n<p>Other than this, the 3 compilers seem remarkably in agreement about how this works.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Sting<\/h2>\n\n\n\n<p>So what does this mean? If we have a compile-time value, and we wrap it in <code>constexpr_value<\/code>, we have potentially the following situation:<\/p>\n\n\n\n<p>The variable declaration is not marked <code>constexpr<\/code>. The function parameter isn&#8217;t <code>constexpr<\/code>. The function itself isn&#8217;t marked <code>constexpr<\/code>, and it&#8217;s not an immediate function. But arbitrarily we can use the value in a <code>constexpr<\/code> context. We can call into a <code>constexpr<\/code> or immediate function. We can use the value in a <code>static_assert<\/code>. We can use the value as a NTTP. And we don&#8217;t have to jump through hoops with less-friendly ways to signal errors in <code>constexpr<\/code> contexts.<\/p>\n\n\n\n<p>I&#8217;m not sure of all the potential uses yet, but this is a curious thing.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Set-up In C++, this doesn&#8217;t work: The compiler complains, quite rightly: Despite the fact that twice_square is a constexpr function, its parameter x is not constexpr. We can&#8217;t use it in a static_assert, we can&#8217;t pass it to a template, we can&#8217;t call an immediate (consteval) function with it&#8230;.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1685","post","type-post","status-publish","format-standard","hentry","category-cpp"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1685","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1685"}],"version-history":[{"count":9,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1685\/revisions"}],"predecessor-version":[{"id":1694,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1685\/revisions\/1694"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}