forked from HowardHinnant/papers
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathconstraint_fixes.html
155 lines (139 loc) · 5.54 KB
/
constraint_fixes.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Fixing small-ish functionality gaps in constraints</title>
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
background-color:#E0E0E0;
padding-left: 15px;
padding-right: 15px;
padding-top: 1px;
padding-bottom: 1px;
}
ins {color:#00A000}
del {color:#A00000}
</style>
</head>
<body>
<address align=right>
Document number: P0766R1
<br/>
Audience: EWG
<br/>
<br/>
<a href="mailto:[email protected]">Ville Voutilainen</a><br/>
2017-10-15<br/>
</address>
<hr/>
<h1 align=center>Fixing small-ish functionality gaps in constraints</h1>
<h2>Abstract</h2>
<p>
This paper deals with some small-ish fallout parts of the merge of Concepts into the C++20 working draft; namely, requires-clauses in lambdas, auto as a function parameter type, and requires-clauses in template template parameters.
</p>
<h2>requires-clauses in lambdas</h2>
<p>
Currently, lambdas cannot have requires-clauses. One of the arguments
for that lack I've heard mentioned is that lambdas are supposed to be
short, and requires-clauses make lambdas verbose.
</p>
<p>
The problem with that argument is that it focuses on the wrong thing;
it's, at least to me, much more important that lambdas can be
<ul>
<li>local - in general, lambdas allow me to write function objects
without having to write namespace-scope definitions</li>
<li>refactored from functions, or from functors, or from functor
templates</li>
</ul>
I think it very likely to have function templates that use plain
requires-clauses. If I then want to refactor such a function template
into a polymorphic lambda, I'm now going to face a massive hindrance,
I have to turn the requires-clauses into "proper" Concepts first. I will
need to introduce namespace-scope (Concept) definitions where none
were required before the refactoring.
</p>
<p>
I don't think that's just a consistency issue. I envision writing
implementation-detail function templates with requires-clauses rather
than proper Concepts when such a Concept is not all that reusable.
I will choose to not write a Concept because it's not going to
be a cross-cutting Domain Concept, it's just a simple compile-time
contract of a function. For such uses, the scope of that contract
should be allowed to be as narrow as feasible, and it should not
be forced to be any wider than the scope
of the function parameter declaration.
</p>
<h2>auto as a function parameter type</h2>
<p>
We happily allow auto as a lambda parameter type, in which
case the lambda is polymorphic. We currently don't allow a plain
function to have auto as a parameter type.
</p>
<p>
This, again, hurts refactoring. There's also no ambiguity about
whether such a function is a template, it's obviously
a template, its parameter type is a keyword that suggests
the type can be anything, and that the type is deduced.
</p>
<p>
I'm perfectly willing to admit that this is not a real functionality
gap. I can write an unconstrained template instead of a function
with an auto parameter. The problem there is that none of the arguments
against a terse syntax for a constrained function template hold,
and now I need to do tedious mechanical transformations when doing
a simple refactoring from a polymorphic lambda to a function template. Sure,
for lambdas that capture something, there is a fair amount of
additional mechanical
transformation involved, but for non-capturing lambdas there shouldn't
be.
</p>
<h2>requires-clauses in template template parameters</h2>
<p>
Curiously, our specification doesn't allow requires-clauses
in template template parameters, but the gcc implementation
of the Concepts TS does.
</p>
<p>
Again, in order to constrain a template template parameter
without having to write a namespace-scope concept definition,
we need to support a requires-clause here. Not every constraint
should be a concept.
</p>
<h2>requires-clauses as a migration step</h2>
<p>
From practical adoption experience, I deem it very likely that
the first step in moving from existing constraints to concepts
is to turn enable_ifs into requires-clauses. That's to me a very
good reason to not leave gaps in our support for requires-clauses.
</p>
<p>
There's a perhaps more controversial and a much scarier aspect to it.
Some codebases will need to try and make pre-C++20 and C++20 constraints
look the same on the declaration level. This will mean that macros
get employed, but those macros can't work if there's no syntactic
position that works for an enable_if and a requires-clause. The pre-C++20
constraints can't use the syntactic position for a
constrained-template-parameter, but they can use the syntactic position
for a requires-clause.
</p>
<h2>requires-clauses are necessary, not just a simple rewrite</h2>
There are use cases where using a requires-clause is necessary;
the other syntaxes cannot do what a requires-clause can. A very
prominent example is establishing relations between elements
of multiple packs. Such relationships can currently be
established with functions but not with lambdas. While
a function can be called with multiple 'raw' packs and
a lambda can't (the first pack must be provided, the subsequent
pack must be deduced), it's still possible to have multiple
wrapped packs:
<blockquote>
<code>
[](tuple<Args1...>, tuple<Args2...>) requires (PackRelation<Args1, Args2> &&...)
</code>
</blockquote>
</body>
</html>