Topic: if requires: the concepts-based if constexpr
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 25 Jun 2016 11:56:40 -0700 (PDT)
Raw View
------=_Part_233_687326043.1466881000829
Content-Type: multipart/alternative;
boundary="----=_Part_234_30921928.1466881000829"
------=_Part_234_30921928.1466881000829
Content-Type: text/plain; charset=UTF-8
Concepts introduces the notion of the `requires` clause: a boolean
expression. C++17 will likely introduce if constexpr, which is a condition
based on a constant expression.
Since requirements are by definition constexpr, it makes sense to be able
to combine the two with:
if requires(...) {...}
Now yes, `requires` clauses are `constexpr`, so it would be possible as is
to use them with `if constexpr`:
if constexpr (requires(...) {...})
But there's no need to say the same thing multiple times. With concepts and
`if constexpr`, I can very easily see people wanting to use them in tandem,
so having shorter syntax is not unreasonable. This is similar to how
`concept` also implies `constexpr`, without us explicitly having to say it.
Consider the visual difference between:
if requires(T a) {a.SomeFunc();}
and
if constexpr(requires(T a) {a.SomeFunc();})
One useful thing here is that we often already have the equivalent of `T a`
somewhere in the program, so most uses of `if requires` would just have an
empty parameter list.
Note that `if requires` would have semantic differences from
`if(requires{...})`. The latter is a regular `if` statement that just so
happens to use a `requires` expression. The former follows the rules of a
true `if constexpr`.
This feature could also be used to give us a way of dealing with the
definition checking issue. One of the issues with definition checking is
that template implementations that are governed by a concept sometimes want
to have optional components. If a type has some function, then it will call
it, but types which don't have that function are OK as well. Such things
are not listed in the concept's constraints because it is something which
all types can fulfill. That is, there is no actual constraint requirement;
it is a semantic constraint rather than a syntactic one.
The usual way of definition testing is to match the expressions in the
constraint with the dependent expressions used in the template. Those which
don't match the constraint requirements are illegal. This would prevent the
use of such optional features, since by definition they would not be listed
in the constraint requirements.
By wrapping such expressions in an `if requires` clause, we're effectively
saying that we are adding to the list of expressions that we permit within
the template. The reason being that the conditional makes sure that the
implementation provides an alternative if the functionality is not present.
So if you want to log certain information, and your `Log` function is
intended to accept any type, you would do this:
if requires() {Log(a);}
{
Log(a);
}
If it turns out that someone provides some type that uses specializations
to prevent `Log` from being called on it, then the `requires` clause will
be false and the function will not be called. If you want that to be a
compile error, you can still do so:
if requires() {Log(a);}
{
Log(a);
}
else
static_assert(false, "Why did you do that?");
We could improve this by making it require less repetition:
if requires
{
Log(a);
}
Since a `requires` expression normally needs a parameter list, the use of
`if requires` without such a list has special meaning. It should mean that
all of the (dependent) expressions in the `if` statement body should be
considered part of the `requires` clause. Therefore, if any of those
requirements are not met, the `requires` clause yields `false`, and the
`else` clause triggers (if any).
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4abc24%40isocpp.org.
------=_Part_234_30921928.1466881000829
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Concepts introduces the notion of the `requires` clause: a=
boolean expression. C++17 will likely introduce if constexpr, which is a c=
ondition based on a constant expression.<br><br>Since requirements are by d=
efinition constexpr, it makes sense to be able to combine the two with:<br>=
<br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250=
); border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px=
; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpret=
typrint"><span style=3D"color: #008;" class=3D"styled-by-prettify">if</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> requires</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(...)</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">{...}</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>No=
w yes, `requires` clauses are `constexpr`, so it would be possible as is to=
use them with `if constexpr`:<br><br><div class=3D"prettyprint" style=3D"b=
ackground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bord=
er-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"=
prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">if</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">constexpr</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">requires</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">(...)</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">{...})</span></div></code>=
</div><br>But there's no need to say the same thing multiple times. Wit=
h concepts and `if constexpr`, I can very easily see people wanting to use =
them in tandem, so having shorter syntax is not unreasonable. This is simil=
ar to how `concept` also implies `constexpr`, without us explicitly having =
to say it.<br><br>Consider the visual difference between:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
style=3D"color: #008;" class=3D"styled-by-prettify">if</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> requires</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">T a</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</=
span><span style=3D"color: #606;" class=3D"styled-by-prettify">SomeFunc</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">();}</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></c=
ode></div><br>and<br><br><div class=3D"prettyprint" style=3D"background-col=
or: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: sol=
id; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint">=
<div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-=
by-prettify">if</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">cons=
texpr</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">requires</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">T a</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">a</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">.</span><span style=3D"color: #606;" class=3D"styled-by-prettify">So=
meFunc</span><span style=3D"color: #660;" class=3D"styled-by-prettify">();}=
)</span></div></code></div><br>One useful thing here is that we often alrea=
dy have the equivalent of `T a` somewhere in the program, so most uses of `=
if requires` would just have an empty parameter list.<br><br>Note that `if =
requires` would have semantic differences from `if(requires{...})`. The lat=
ter is a regular `if` statement that just so happens to use a `requires` ex=
pression. The former follows the rules of a true `if constexpr`.<br><br>Thi=
s feature could also be used to give us a way of dealing with the definitio=
n checking issue. One of the issues with definition checking is that templa=
te implementations that are governed by a concept sometimes want to have op=
tional components. If a type has some function, then it will call it, but t=
ypes which don't have that function are OK as well.=C2=A0 Such things a=
re not listed in the concept's constraints because it is something whic=
h all types can fulfill. That is, there is no actual constraint requirement=
; it is a semantic constraint rather than a syntactic one.<br><br>The usual=
way of definition testing is to match the expressions in the constraint wi=
th the dependent expressions used in the template. Those which don't ma=
tch the constraint requirements are illegal. This would prevent the use of =
such optional features, since by definition they would not be listed in the=
constraint requirements.<br><br>By wrapping such expressions in an `if req=
uires` clause, we're effectively saying that we are adding to the list =
of expressions that we permit within the template. The reason being that th=
e conditional makes sure that the implementation provides an alternative if=
the functionality is not present. So if you want to log certain informatio=
n, and your `Log` function is intended to accept any type, you would do thi=
s:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 25=
0, 250); border-color: rgb(187, 187, 187); border-style: solid; border-widt=
h: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"s=
ubprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">if=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> requires<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">Log</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">a</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">);}</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Log</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">}</span></div></code></div><br>If it turns ou=
t that someone provides some type that uses specializations to prevent `Log=
` from being called on it, then the `requires` clause will be false and the=
function will not be called. If you want that to be a compile error, you c=
an still do so:<br><br><div class=3D"prettyprint" style=3D"background-color=
: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid=
; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><d=
iv class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by=
-prettify">if</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> requires</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">()</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span s=
tyle=3D"color: #606;" class=3D"styled-by-prettify">Log</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">a</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">);}</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>=C2=A0 </span><span style=3D"color: #606;" class=3D"styled-by-prett=
ify">Log</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">else</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">static_assert</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">false</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"Wh=
y did you do that?"</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">);</span></div></code></div><br>We could improve this by maki=
ng it require less repetition:<br><br><div class=3D"prettyprint" style=3D"b=
ackground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bord=
er-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"=
prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">if</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> requires<br></span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br>=C2=A0 </span><span style=3D"color: #606;" class=3D"styled-=
by-prettify">Log</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">}</span></div></code></div=
><br>Since a `requires` expression normally needs a parameter list, the use=
of `if requires` without such a list has special meaning. It should mean t=
hat all of the (dependent) expressions in the `if` statement body should be=
considered part of the `requires` clause. Therefore, if any of those requi=
rements are not met, the `requires` clause yields `false`, and the `else` c=
lause triggers (if any).<br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4abc24%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4abc24=
%40isocpp.org</a>.<br />
------=_Part_234_30921928.1466881000829--
------=_Part_233_687326043.1466881000829--
.
Author: Zhihao Yuan <zy@miator.net>
Date: Sat, 25 Jun 2016 14:21:54 -0500
Raw View
On Sat, Jun 25, 2016 at 1:56 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
> Consider the visual difference between:
>
> if requires(T a) {a.SomeFunc();}
>
> and
>
> if constexpr(requires(T a) {a.SomeFunc();})
>
#define required(expr, ...) constexpr (requires(__VA_ARGS__) { expr; })
if required(a.SomeFunc(), T a)
do_something();
if required(Log(a))
Log(a);
// gcc -E
if constexpr (requires(T a) { a.SomeFunc(); })
do_something();
if constexpr (requires() { Log(a); })
Log(a);
> else
> static_assert(false, "Why did you do that?");
Not supported in C++17. Papers fixing static_assert's
interaction with constexpr if are welcome.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://blog.miator.net/
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAGsORuBLuE0UbQDzmxus%2ByWve916%2BpTLqnJJSs6a3GfLQYzaUQ%40mail.gmail.com.
.
Author: Tom Honermann <tom@honermann.net>
Date: Sun, 26 Jun 2016 18:03:24 -0400
Raw View
This is a multi-part message in MIME format.
--------------040107090800060603070604
Content-Type: text/plain; charset=UTF-8; format=flowed
This idea came up previously [1], but to my knowledge has not been
discussed as thoroughly as you presented here. The following example
was provided in that email thread:
template<InputIterator I>
I advance(I i, int n) {
if requires(RandomAccessIterator<I>()) {
i += n;
} else {
while (n > 0)
++i;
}
}
The above does use a different syntax then what you proposed. Rather
than using a requires expression with the if statement, the above uses a
requires clause. I find the above more natural, though it does open the
door to cases of 'requires requires' if one wants to add requirements
based on arbitrary expressions rather than on a constraint-expression.
I agree with your presentation of the semantic differences between 'if
requires' and 'if constexpr(requires {})'. In particular, the former is
explicit that a constraint is being added to (a portion of) the function
definition and, in a definition checking future, it seems reasonable to
then restrict uses of expressions that would otherwise fail a constraint
check to the body of the if statement. In the latter case, it is not
obvious to me whether such expressions could be used in the 'if
constexpr' condition (e.g., in a conjunction following the requires
expression), or would be restricted to the statement body. I would
expect a compiler's ability to reason about the constraints to be
simpler for the former case as well.
I'm not sure about the idea to implicitly allow any expressions used in
the statement body if the 'if requires' doesn't explicitly list
constraints. It seems like that would require speculative instantiation
which, as I understand it, would be difficult for at least some
implementors.
I do like this approach and have been intending to write a paper about
it, but time and energy... I think a feature like this is necessary for
template definition checking to become a reality with the current
Concepts proposal.
Tom.
[1]: On the EWG reflector, email thread titled "constexpr if and concept
definition checking", 2016-02-26.
On 06/25/2016 02:56 PM, Nicol Bolas wrote:
> Concepts introduces the notion of the `requires` clause: a boolean
> expression. C++17 will likely introduce if constexpr, which is a
> condition based on a constant expression.
>
> Since requirements are by definition constexpr, it makes sense to be
> able to combine the two with:
>
> |
> ifrequires(...){...}
> |
>
> Now yes, `requires` clauses are `constexpr`, so it would be possible
> as is to use them with `if constexpr`:
>
> |
> ifconstexpr(requires(...){...})
> |
>
> But there's no need to say the same thing multiple times. With
> concepts and `if constexpr`, I can very easily see people wanting to
> use them in tandem, so having shorter syntax is not unreasonable. This
> is similar to how `concept` also implies `constexpr`, without us
> explicitly having to say it.
>
> Consider the visual difference between:
>
> |
> ifrequires(T a){a.SomeFunc();}
> |
>
> and
>
> |
> ifconstexpr(requires(T a){a.SomeFunc();})
> |
>
> One useful thing here is that we often already have the equivalent of
> `T a` somewhere in the program, so most uses of `if requires` would
> just have an empty parameter list.
>
> Note that `if requires` would have semantic differences from
> `if(requires{...})`. The latter is a regular `if` statement that just
> so happens to use a `requires` expression. The former follows the
> rules of a true `if constexpr`.
>
> This feature could also be used to give us a way of dealing with the
> definition checking issue. One of the issues with definition checking
> is that template implementations that are governed by a concept
> sometimes want to have optional components. If a type has some
> function, then it will call it, but types which don't have that
> function are OK as well. Such things are not listed in the concept's
> constraints because it is something which all types can fulfill. That
> is, there is no actual constraint requirement; it is a semantic
> constraint rather than a syntactic one.
>
> The usual way of definition testing is to match the expressions in the
> constraint with the dependent expressions used in the template. Those
> which don't match the constraint requirements are illegal. This would
> prevent the use of such optional features, since by definition they
> would not be listed in the constraint requirements.
>
> By wrapping such expressions in an `if requires` clause, we're
> effectively saying that we are adding to the list of expressions that
> we permit within the template. The reason being that the conditional
> makes sure that the implementation provides an alternative if the
> functionality is not present. So if you want to log certain
> information, and your `Log` function is intended to accept any type,
> you would do this:
>
> |
> ifrequires(){Log(a);}
> {
> Log(a);
> }
> |
>
> If it turns out that someone provides some type that uses
> specializations to prevent `Log` from being called on it, then the
> `requires` clause will be false and the function will not be called.
> If you want that to be a compile error, you can still do so:
>
> |
> ifrequires(){Log(a);}
> {
> Log(a);
> }
> else
> static_assert(false,"Why did you do that?");
> |
>
> We could improve this by making it require less repetition:
>
> |
> ifrequires
> {
> Log(a);
> }
> |
>
> Since a `requires` expression normally needs a parameter list, the use
> of `if requires` without such a list has special meaning. It should
> mean that all of the (dependent) expressions in the `if` statement
> body should be considered part of the `requires` clause. Therefore, if
> any of those requirements are not met, the `requires` clause yields
> `false`, and the `else` clause triggers (if any).
> --
> 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-proposals+unsubscribe@isocpp.org
> <mailto:std-proposals+unsubscribe@isocpp.org>.
> To post to this group, send email to std-proposals@isocpp.org
> <mailto:std-proposals@isocpp.org>.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4abc24%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4abc24%40isocpp.org?utm_medium=email&utm_source=footer>.
--
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-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/5770512C.6090401%40honermann.net.
--------------040107090800060603070604
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">This idea came up previously [1], but
to my knowledge has not been discussed as thoroughly as you
presented here.=C2=A0 The following example was provided in that emai=
l
thread:<br>
<br>
template<InputIterator I>
<br>
I advance(I i, int n) {
<br>
=C2=A0 if requires(RandomAccessIterator<I>()) {
<br>
=C2=A0=C2=A0=C2=A0 i +=3D n;
<br>
=C2=A0 } else {
<br>
=C2=A0=C2=A0=C2=A0 while (n > 0)
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ++i;
<br>
=C2=A0 }
<br>
}
<br>
<br>
The above does use a different syntax then what you proposed.=C2=A0
Rather than using a requires expression with the if statement, the
above uses a requires clause.=C2=A0 I find the above more natural,
though it does open the door to cases of 'requires requires' if
one wants to add requirements based on arbitrary expressions
rather than on a constraint-expression.<br>
<br>
I agree with your presentation of the semantic differences between
'if requires' and 'if constexpr(requires {})'.=C2=A0 In particular, t=
he
former is explicit that a constraint is being added to (a portion
of) the function definition and, in a definition checking future,
it seems reasonable to then restrict uses of expressions that
would otherwise fail a constraint check to the body of the if
statement.=C2=A0 In the latter case, it is not obvious to me whether
such expressions could be used in the 'if constexpr' condition
(e.g., in a conjunction following the requires expression), or
would be restricted to the statement body.=C2=A0 I would expect a
compiler's ability to reason about the constraints to be simpler
for the former case as well.<br>
<br>
I'm not sure about the idea to implicitly allow any expressions
used in the statement body if the 'if requires' doesn't explicitly
list constraints.=C2=A0 It seems like that would require speculative
instantiation which, as I understand it, would be difficult for at
least some implementors.<br>
<br>
I do like this approach and have been intending to write a paper
about it, but time and energy...=C2=A0 I think a feature like this is
necessary for template definition checking to become a reality
with the current Concepts proposal.<br>
<br>
Tom.<br>
<br>
[1]: On the EWG reflector, email thread titled "constexpr if and
concept definition checking", 2016-02-26.<br>
<br>
On 06/25/2016 02:56 PM, Nicol Bolas wrote:<br>
</div>
<blockquote
cite=3D"mid:97c876f2-bde5-4555-a18d-3bae8c4abc24@isocpp.org"
type=3D"cite">
<div dir=3D"ltr">Concepts introduces the notion of the `requires`
clause: a boolean expression. C++17 will likely introduce if
constexpr, which is a condition based on a constant expression.<br>
<br>
Since requirements are by definition constexpr, it makes sense
to be able to combine the two with:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> requires</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(...)</=
span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{...}</=
span><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span></div>
</code></div>
<br>
Now yes, `requires` clauses are `constexpr`, so it would be
possible as is to use them with `if constexpr`:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> </span><span
style=3D"color: #008;" class=3D"styled-by-prettify">constex=
pr</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">require=
s</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(...)</=
span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{...})<=
/span></div>
</code></div>
<br>
But there's no need to say the same thing multiple times. With
concepts and `if constexpr`, I can very easily see people
wanting to use them in tandem, so having shorter syntax is not
unreasonable. This is similar to how `concept` also implies
`constexpr`, without us explicitly having to say it.<br>
<br>
Consider the visual difference between:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> requires</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">T a</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">)</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">.</span=
><span
style=3D"color: #606;" class=3D"styled-by-prettify">SomeFun=
c</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">();}</s=
pan><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span></div>
</code></div>
<br>
and<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> </span><span
style=3D"color: #008;" class=3D"styled-by-prettify">constex=
pr</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">require=
s</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">T a</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">)</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">.</span=
><span
style=3D"color: #606;" class=3D"styled-by-prettify">SomeFun=
c</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">();})</=
span></div>
</code></div>
<br>
One useful thing here is that we often already have the
equivalent of `T a` somewhere in the program, so most uses of
`if requires` would just have an empty parameter list.<br>
<br>
Note that `if requires` would have semantic differences from
`if(requires{...})`. The latter is a regular `if` statement that
just so happens to use a `requires` expression. The former
follows the rules of a true `if constexpr`.<br>
<br>
This feature could also be used to give us a way of dealing with
the definition checking issue. One of the issues with definition
checking is that template implementations that are governed by a
concept sometimes want to have optional components. If a type
has some function, then it will call it, but types which don't
have that function are OK as well.=C2=A0 Such things are not listed
in the concept's constraints because it is something which all
types can fulfill. That is, there is no actual constraint
requirement; it is a semantic constraint rather than a syntactic
one.<br>
<br>
The usual way of definition testing is to match the expressions
in the constraint with the dependent expressions used in the
template. Those which don't match the constraint requirements
are illegal. This would prevent the use of such optional
features, since by definition they would not be listed in the
constraint requirements.<br>
<br>
By wrapping such expressions in an `if requires` clause, we're
effectively saying that we are adding to the list of expressions
that we permit within the template. The reason being that the
conditional makes sure that the implementation provides an
alternative if the functionality is not present. So if you want
to log certain information, and your `Log` function is intended
to accept any type, you would do this:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> requires</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">()</spa=
n><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span
style=3D"color: #606;" class=3D"styled-by-prettify">Log</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">);}</sp=
an><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">{</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
=C2=A0 </span><span style=3D"color: #606;"
class=3D"styled-by-prettify">Log</span><span style=3D"color=
:
#660;" class=3D"styled-by-prettify">(</span><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">);</spa=
n><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">}</span></div>
</code></div>
<br>
If it turns out that someone provides some type that uses
specializations to prevent `Log` from being called on it, then
the `requires` clause will be false and the function will not be
called. If you want that to be a compile error, you can still do
so:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> requires</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">()</spa=
n><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span
style=3D"color: #606;" class=3D"styled-by-prettify">Log</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">);}</sp=
an><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">{</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
=C2=A0 </span><span style=3D"color: #606;"
class=3D"styled-by-prettify">Log</span><span style=3D"color=
:
#660;" class=3D"styled-by-prettify">(</span><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">);</spa=
n><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">}</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #008;"
class=3D"styled-by-prettify">else</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
=C2=A0 </span><span style=3D"color: #008;"
class=3D"styled-by-prettify">static_assert</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #008;" class=3D"styled-by-prettify">false</=
span><span
style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #080;" class=3D"styled-by-prettify">"Why di=
d
you do that?"</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">);</span></div>
</code></div>
<br>
We could improve this by making it require less repetition:<br>
<br>
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,
250); border-color: rgb(187, 187, 187); border-style: solid;
border-width: 1px; word-wrap: break-word;"><code
class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">if</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> requires<br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">{</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
=C2=A0 </span><span style=3D"color: #606;"
class=3D"styled-by-prettify">Log</span><span style=3D"color=
:
#660;" class=3D"styled-by-prettify">(</span><span
style=3D"color: #000;" class=3D"styled-by-prettify">a</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">);</spa=
n><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">}</span></div>
</code></div>
<br>
Since a `requires` expression normally needs a parameter list,
the use of `if requires` without such a list has special
meaning. It should mean that all of the (dependent) expressions
in the `if` statement body should be considered part of the
`requires` clause. Therefore, if any of those requirements are
not met, the `requires` clause yields `false`, and the `else`
clause triggers (if any).<br>
</div>
-- <br>
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it,
send an email to <a moz-do-not-send=3D"true"
href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposals+=
unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a moz-do-not-send=3D"true"
href=3D"mailto:std-proposals@isocpp.org">std-proposals@isocpp.org</=
a>.<br>
To view this discussion on the web visit <a
moz-do-not-send=3D"true"
href=3D"https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/97c876=
f2-bde5-4555-a18d-3bae8c4abc24%40isocpp.org?utm_medium=3Demail&utm_sour=
ce=3Dfooter"><a class=3D"moz-txt-link-freetext" href=3D"https://groups.goog=
le.com/a/isocpp.org/d/msgid/std-proposals/97c876f2-bde5-4555-a18d-3bae8c4ab=
c24%40isocpp.org">https://groups.google.com/a/isocpp.org/d/msgid/std-propos=
als/97c876f2-bde5-4555-a18d-3bae8c4abc24%40isocpp.org</a></a>.<br>
</blockquote>
<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/5770512C.6090401%40honermann.net?utm_=
medium=3Demail&utm_source=3Dfooter">https://groups.google.com/a/isocpp.org/=
d/msgid/std-proposals/5770512C.6090401%40honermann.net</a>.<br />
--------------040107090800060603070604--
.