constexpr if, and a little bit more control over constexpr.

392 views
Skip to first unread message

Andrei L

unread,
Mar 29, 2016, 11:51:35 PM3/29/16
to ISO C++ Standard - Future Proposals
Hello.

At the last committee meeting, there was made a decision to change syntax from 'constexpr if' to 'if constexpr', and while this decision has it's reasons, there is minor issue with it. It is somewhat unclear, what 'if constexpr' is means. I understand what it means but still, I feel urge to read 'if constexpr ... else ....' as: "if constexpr, then do this, if not constexpr, do that." This issue can be solved, if you think about 'constexpr', as part of condition, as a requirement that condition must be constexpr, but syntactically, it is placed outside parentheses, closer to an 'if', than to condition. If we'd have something like 'constexpr ( expression )' in the language, then that form of 'if' could've be explained as 'if (constexpr (condition))', and we could say that since parentheses around constexpr-condition are redundant, we are allowed to drop them.

That made me think: "Why can't we have that constexpr-expression?" Given that there is desire to be able to require compile-time evaluation, I find it quite strange that we don't have something like that already.

Consider:

constexpr int get_val();

void foo(int &);
void bar()
{
  constexpr int val = get_val();
  foo(val);
}

So, we have constexpr functions in the language, and they are not required to be called at compile time. To make sure, that we don't pay cost at run-time for what we can do at compile-time, we assign result of a function call to a constexpr variable. But, constexpr implies const, so presented code will not compile. GCC produces an error: "binding 'const int' to 'int &' discards qualifiers". To overcome that issue we can introduce a temporary:

void bar()
{
  constexpr int tmp = get_val();
  int val = tmp;
  foo(val);
}


Problem solved, but now, we have unneeded and unwanted variable, which has no cost, but it's still there, in the code, takes free space. If we'd had constexpr-expression in a language, we could've solved our problem like this:

void bar()
{
  int val = constexpr (get_val());
  foo(val);
}

What constexpr-expression could do? It could force compile-time evaluation of an expression. If evaluation at compile-time is not possible, then we'd get loud failure, instead of possible run-time errors, or not matching expectations.

So, now t
here is no temporaries, only what's needed, and no run-time cost, but, there is also one more question: "Do we need parentheses around expression in constexpr-expression?"

int val = constexpr get_val();

Without parentheses, 'constexpr' looks like a prefix to an expression, what I find nice, and less noisy.

Coming back to 'if constexpr'; If thinking that 'constexpr' is closer to condition than to an 'if' is the right way to think, then we
can make one step further and put 'constexpr' inside parentheses.

if (constexpr condition) {
  ...
}


It's far from how 'static_if' or 'constexpr if' looks, but nor 'if constexpr' looks like them. This syntax, in my opinion, is less ambiguous in it's "if-ness", then 'if constexpr'.

Thoughts?
possible-grammar.txt

bruno....@gmail.com

unread,
Mar 30, 2016, 5:04:50 AM3/30/16
to ISO C++ Standard - Future Proposals
Would that be allowed to work on constexpr function parameters?

constexpr int bar (int x)
{
     
return x;
}

constexpr int foo (int x)
{
     
constexpr int j = constexpr (x);
     
return bar(j);
}
int x = constexpr foo(11);

Andrei L

unread,
Mar 30, 2016, 11:20:54 AM3/30/16
to std-pr...@isocpp.org

2016-03-30 14:04 GMT+05:00 <bruno....@gmail.com>:
Would that be allowed to work on constexpr function parameters?

I think it's not, because its purpose is to request a guarantee that there will be no run-time.


constexpr int foo (int x)
{
     constexpr int j = constexpr (x);
     return bar(j);
}

In this case, it is impossible to guarantee that 'x' always will be constexpr, and i don't think that this is the right way to specify constexpr-only function.

Richard Smith

unread,
Mar 30, 2016, 4:00:58 PM3/30/16
to std-pr...@isocpp.org
On Tue, Mar 29, 2016 at 8:51 PM, Andrei L <aend...@gmail.com> wrote:
> Hello.
>
> At the last committee meeting, there was made a decision to change syntax
> from 'constexpr if' to 'if constexpr', and while this decision has it's
> reasons, there is minor issue with it. It is somewhat unclear, what 'if
> constexpr' is means. I understand what it means but still, I feel urge to
> read 'if constexpr ... else ....' as: "if constexpr, then do this, if not
> constexpr, do that." This issue can be solved, if you think about
> 'constexpr', as part of condition, as a requirement that condition must be
> constexpr, but syntactically, it is placed outside parentheses, closer to an
> 'if', than to condition. If we'd have something like 'constexpr ( expression
> )' in the language, then that form of 'if' could've be explained as 'if
> (constexpr (condition))', and we could say that since parentheses around
> constexpr-condition are redundant, we are allowed to drop them.
>
> That made me think: "Why can't we have that constexpr-expression?" Given
> that there is desire to be able to require compile-time evaluation, I find
> it quite strange that we don't have something like that already.
>
> Consider:
>
> constexpr int get_val();
>
> void foo(int &);
> void bar()
> {
> constexpr int val = get_val();

You can do this:

constexpr int &&val = get_val();
> --
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/33d19c42-848a-4952-9724-26b98790742b%40isocpp.org.

Andrei L

unread,
Mar 30, 2016, 4:16:36 PM3/30/16
to std-pr...@isocpp.org

2016-03-31 1:00 GMT+05:00 Richard Smith <ric...@metafoo.co.uk>:
You can do this:

constexpr int &&val = get_val();

Correct me if I'm wrong, but type of 'val' would be 'const int &&'. I don't see how i can use that to call 'foo(int &)'. Also

GCC produced:
prog.cc: In function 'int main()':
prog.cc:13:33: error: '<anonymous>' is not a constant expression
   constexpr int &&val = get_val();
                                 ^
Clang produced:
prog.cc:13:19: error: constexpr variable 'val' must be initialized by a constant expression
  constexpr int &&val = get_val();
                  ^     ~~~~~~~~~
prog.cc:13:19: note: reference to temporary is not a constant expression
prog.cc:13:25: note: temporary created here
  constexpr int &&val = get_val();
                        ^

Richard Smith

unread,
Mar 30, 2016, 4:33:03 PM3/30/16
to std-pr...@isocpp.org
On Wed, Mar 30, 2016 at 1:15 PM, Andrei L <aend...@gmail.com> wrote:
>
> 2016-03-31 1:00 GMT+05:00 Richard Smith <ric...@metafoo.co.uk>:
>>
>> You can do this:
>>
>> constexpr int &&val = get_val();
>
>
> Correct me if I'm wrong, but type of 'val' would be 'const int &&'. I don't
> see how i can use that to call 'foo(int &)'.

You're wrong :) The type of 'val' would be 'int &&'.

> Also
>
> GCC produced:
>
> prog.cc: In function 'int main()':
> prog.cc:13:33: error: '<anonymous>' is not a constant expression
> constexpr int &&val = get_val();
> ^
>
> Clang produced:
>
> prog.cc:13:19: error: constexpr variable 'val' must be initialized by a
> constant expression
> constexpr int &&val = get_val();
> ^ ~~~~~~~~~
> prog.cc:13:19: note: reference to temporary is not a constant expression
> prog.cc:13:25: note: temporary created here
> constexpr int &&val = get_val();
> ^

Ah right, you also need to make it static. Sorry about that :)

Andrei L

unread,
Mar 30, 2016, 7:54:25 PM3/30/16
to std-pr...@isocpp.org

2016-03-31 1:32 GMT+05:00 Richard Smith <ric...@metafoo.co.uk>:
The type of 'val' would be 'int &&'

Oh. Is 'constexpr' applies 'const' to whole thing? i.e. 'int && const'?


Ah right, you also need to make it static. Sorry about that :)

Heh :)

After jumping through 'static' and '&&', we got what we wanted, but not quite. We turned simple local variable into static one.

Don't get me wrong. I don't think that using temporary variable is bad. For example, if we have 'a(b(c(d(e(f(g()))))))', then, to make that readable, we can make bunch of temporaries to store intermediate results and use them in next consequential calls (UFCS could help us here). Temporary is just an annoyance and it would be nice to get rid of it.

Johannes Schaub

unread,
Mar 31, 2016, 11:23:54 AM3/31/16
to std-pr...@isocpp.org

I think of "if constexpr .. else .." as

  if .. always holds then .. otherwise if it never holds.. otherwise error

Note that the "otherwise if" corresponds to "else". Not "else if" which would be "else if it never holds then if". I.e the "constexpr" determines a dependency mode for "if" which affects both branches.

Therefore the "constexpr" for else is not implied for me. Now if you put the "constexpr" into the condition, then that reads to me as

   if .. neither always nor never holds then error otherwise whenever it holds .. otherwise whenever it doesn't hold...

Here, the "constexpr" just validates that we know of the constness similar to puttting the condition into "sizeof(char[1+cond])". But it doesn't affect the dependency mode: It's still checked with the dynamic control flow.

Johannes Schaub

unread,
Mar 31, 2016, 11:27:36 AM3/31/16
to std-pr...@isocpp.org


Am 31.03.2016 01:54 schrieb "Andrei L" <aend...@gmail.com>:
>
>
> 2016-03-31 1:32 GMT+05:00 Richard Smith <ric...@metafoo.co.uk>:
>>
>> The type of 'val' would be 'int &&'
>
>
> Oh. Is 'constexpr' applies 'const' to whole thing? i.e. 'int && const'?
>

I think it does that only for declarations of objects (i.e for object declarations with nonreference types).

Paul Fultz II

unread,
Apr 4, 2016, 4:52:18 PM4/4/16
to ISO C++ Standard - Future Proposals


On Wednesday, March 30, 2016 at 6:54:25 PM UTC-5, Andrei L wrote:

2016-03-31 1:32 GMT+05:00 Richard Smith <ric...@metafoo.co.uk>:
The type of 'val' would be 'int &&'

Oh. Is 'constexpr' applies 'const' to whole thing? i.e. 'int && const'?

Ah right, you also need to make it static. Sorry about that :)

Heh :)

After jumping through 'static' and '&&', we got what we wanted, but not quite. We turned simple local variable into static one.

That is exactly what `constexpr if` is, it is `static_if` because the value must be known statically. For example, this won't work:

template<class T, class U>
constexpr auto pick(bool b, T x, U y)
{
    if constexpr(b) return x;
    else return y;
}

Even though the variable `b` can be know at compile-time, this won't work because the function returns a different type depending on whether the boolean is true or not. This can be fixed by using a static boolean instead, like this:

template<bool B, class T, class U>
constexpr auto pick(T x, U y)
{
    if constexpr(B) return x;
    else return y;
}

Or use an integral constant, which stores its value statically as well:

template<class IntegralConstant, class T, class U>
constexpr auto pick(IntegralConstant b, T x, U y)
{
    if constexpr(b) return x;
    else return y;
}

Ultimately, I think the use of `constexpr if` is a poor term to use, causes confusion, and does not accurately describe what is required(that is the value must be known at compile-time *and* static). No doubt, `static_if` would better describe it and would be more consistent with the rest of the language(such as `static_assert`), however, there seems to be political issues with that name. Perhaps a better option could be to use something like angle brackets, since template parameters require compile-time values that are static:

template<bool B, class T, class U>
constexpr auto pick(T x, U y)
{
    if<B>
    {
        return x;
    }
    else
    {
        return y;
    }
}

Paul

Ville Voutilainen

unread,
Apr 4, 2016, 5:07:21 PM4/4/16
to ISO C++ Standard - Future Proposals
On 4 April 2016 at 23:52, Paul Fultz II <pful...@gmail.com> wrote:
> Ultimately, I think the use of `constexpr if` is a poor term to use, causes
> confusion, and does not accurately describe what is required(that is the
> value must be known at compile-time *and* static). No doubt, `static_if`
> would better describe it and would be more consistent with the rest of the
> language(such as `static_assert`), however, there seems to be political
> issues with that name. Perhaps a better option could be to use something
> like angle brackets, since template parameters require compile-time values
> that are static:


For what it's worth, I decided against keeping calling it static_if (as I did
in http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4461.html), because
it's not the static if e.g. D has; a constexpr if has a much narrower
focus and can't
do all the bells and whistles D's static if can. My papers explain
why, but tl;dr is that
it turned out to be very hard to have such a control statement outside
a block scope,
and the issue of whether it should or should not establish a new scope
wasn't entirely
understood in Kona 2012, but became much better understood since.

I don't see the problem with "if constexpr". Sure, you can think of it
as "the condition
must be compile-time and static", I think of it as "the condition must
be a constant expression
convertible to bool". A "static" doesn't seem to describe that any
better, quite the opposite.

Paul Fultz II

unread,
Apr 4, 2016, 9:35:22 PM4/4/16
to ISO C++ Standard - Future Proposals


On Monday, April 4, 2016 at 4:07:21 PM UTC-5, Ville Voutilainen wrote:
On 4 April 2016 at 23:52, Paul Fultz II <pful...@gmail.com> wrote:
> Ultimately, I think the use of `constexpr if` is a poor term to use, causes
> confusion, and does not accurately describe what is required(that is the
> value must be known at compile-time *and* static). No doubt, `static_if`
> would better describe it and would be more consistent with the rest of the
> language(such as `static_assert`), however, there seems to be political
> issues with that name. Perhaps a better option could be to use something
> like angle brackets, since template parameters require compile-time values
> that are static:


For what it's worth, I decided against keeping calling it static_if (as I did
in http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4461.html), because
it's not the static if e.g. D has; a constexpr if has a much narrower
focus and can't
do all the bells and whistles D's static if can. My papers explain
why, but tl;dr is that
it turned out to be very hard to have such a control statement outside
a block scope,
and the issue of whether it should or should not establish a new scope
wasn't entirely
understood in Kona 2012, but became much better understood since.

Most don't expect static_if to work like it does in D. When most people talk about emulating static_if in C++, it works like the so called `constexpr if` thats being proposed.
 

I don't see the problem with "if constexpr".
Sure, you can think of it
as "the condition
must be compile-time and static", 
I think of it as "the condition must
be a constant expression
convertible to bool". 

Should `constexpr` always imply `static`, then? For example, this is not valid because it is not a constant expression:

constexpr void foo(bool b)
{
    constexpr bool r = b;
}

However, using an integral constant it is:

template<class IntegralConstant>
constexpr void foo(IntegralConstant b)
{
    constexpr bool r = b;
}

However, the example Richard Smith gave required `static`. Perhaps to make it clearer, `constexpr` variables should always imply `static`. This way `constexpr(...)` is like declaring an anonymous `constexpr` variable(which of course would mean its `static` as well). Would it ever make sense to have `constexpr` variables to be non-static?
 
A "static" doesn't seem to describe that any
better, quite the opposite.

It describes it the same way as static_assert. 

Andrei L

unread,
Apr 5, 2016, 6:05:35 AM4/5/16
to std-pr...@isocpp.org

2016-04-05 6:35 GMT+05:00 Paul Fultz II <pful...@gmail.com>:

However, the example Richard Smith gave required `static`.

The goal was to get non-const, non-static local variable initialized by result of constexpr function called at compile-time.

Perhaps to make it clearer, `constexpr` variables should always imply `static`. <..> Would it ever make sense to have `constexpr` variables to be non-static?

I fail to see what compile-time constant has to do with linkage or storage duration. Are you mixing meaning of `constexpr` and `static` in the language and meaning of `static` outside the language?


This way `constexpr(...)` is like declaring an anonymous `constexpr` variable(which of course would mean its `static` as well).

I don't think it should declare or act like it's declaring something. I think it should be just an assertion that something is going to be evaluated at compile-time, a strong guarantee.

Paul Fultz II

unread,
Apr 5, 2016, 12:30:46 PM4/5/16
to ISO C++ Standard - Future Proposals


On Tuesday, April 5, 2016 at 5:05:35 AM UTC-5, Andrei L wrote:

2016-04-05 6:35 GMT+05:00 Paul Fultz II <pful...@gmail.com>:

However, the example Richard Smith gave required `static`.

The goal was to get non-const, non-static local variable initialized by result of constexpr function called at compile-time.

A `constexpr` variable or expression can be used directly in an array or template parameter, so it must be static. Otherwise, why not use a local variable in a constexpr function or even a template function?
 

Perhaps to make it clearer, `constexpr` variables should always imply `static`. <..> Would it ever make sense to have `constexpr` variables to be non-static?

I fail to see what compile-time constant has to do with linkage or storage duration. Are you mixing meaning of `constexpr` and `static` in the language and meaning of `static` outside the language?

Like I said, constexpr variables require static storage duration. Instead of requiring `static constexpr x = ...;`, static duration should be implicit with `constexpr` variables. So then the `static` keyword could be omitted and it can be written like: `constexpr x = ...;`. This would make it consistent with the `constexpr(...)` construct used with `if constexpr(...)` since that requires static duration as well.
 

This way `constexpr(...)` is like declaring an anonymous `constexpr` variable(which of course would mean its `static` as well).

I don't think it should declare or act like it's declaring something. I think it should be just an assertion that something is going to be evaluated at compile-time, a strong guarantee.

But for `constexpr(...)` to assert compile-time evaluation it should be both consistent with `if constexpr(...)` and `constexpr` variables, which both require static storage duration. So it makes sense to describe it as declaring a `constexpr` variable.

A better way to say it, would be that `constexpr(...)` is equivalent to `[]{ static constexpr auto&& x = ...; return x; }`. Even more so, if `constexpr` implies `static`, it could be written just as: `[]{ constexpr auto&& x = ...; return x; }`, which I think it makes it more consistent. Plus, I don't think it would ever makes sense to have a non-static `constexpr` variables.

Paul

Andrei L

unread,
Apr 5, 2016, 1:22:43 PM4/5/16
to std-pr...@isocpp.org

2016-04-05 21:30 GMT+05:00 Paul Fultz II <pful...@gmail.com>:
A `constexpr` variable or expression can be used directly in an array or template parameter, so it must be static.

Ah, i get it.

There are static variables. There are static constants. `static int val` is a static variable. `constexpr int val` is a static constant. `static` here `static` there, but those two are different. One changes storage duration, other one implied by definition. `constexpr` is already static, but in different sense.
Reply all
Reply to author
Forward
0 new messages