File: parampack.yo

package info (click to toggle)
c%2B%2B-annotations 11.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 11,244 kB
  • sloc: cpp: 21,698; makefile: 1,505; ansic: 165; sh: 121; perl: 90
file content (73 lines) | stat: -rw-r--r-- 3,917 bytes parent folder | download | duplicates (3)
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
As we have seen (cf. section ref(CXXMULTI)) concepts may process 
template parameter packs. Such concepts are called 
    hi(concept: variadic) emi(variadic concepts).  When defining
concept-protected variadic function or class templates variadic concepts
aren't always required. Consider the following function:
    verbinsert(-s4 //sumfun examples/parampacks.cc)

Here we see a variadic template, but it defines all its parameters as
constrained types by simply mentioning the concept tt(HasSize) instead of just 
tt(typename). The tt(HasSize) concept is very basic: it merely requires that
tt(type.size()) exists, returning a tt(size_t):
    verbinsert(-s4 //hassize examples/parampacks.cc)

Once tt(fun) has verified that all its argument types satisfy the tt(HasSize)
requirements no additional checks are necessary. The tt(fun) function
template merely forwards its arguments to tt(sum), a variadic template, that
simply adds the return values of the tt(size()) members of its arguments:
    verbinsert(-s4 //sum examples/parampacks.cc)

The wrapper function tt(fun) isn't really required. The variadic template
function summing the various tt(size()) values itself can also be defined so
that its types themselves must satisfy the tt(HasSize) concept. Here is the
definition of the variadic function template tt(sum2) requiring precisely
that:
    verbinsert(-s4 //sum2 examples/parampacks.cc)

And here is a tt(main) function calling tt(fun) and tt(sum2):
    verbinsert(-s4 //main examples/parampacks.cc)

On the other hand, the predefined concept tt(std::constructible_from) em(is) a
variadic concept, as it accepts a LHS template parameter and a RHS parameter
pack. This concept is satisfied if the LHS parameter can be constructed
from the types specified in its RHS parameter pack. After including
tt(type_trait) defining and using such a concept is not very hard:
    verbinsert(-s4 //constructible examples/constructiblefrom.cc)

The recipe for writing variadic concepts is not very complex:
    itemization(
    it() start the concept's definition with a template header specifying a
        parameter pack; 
    it() pass the parameters to a type trait handling the pack;
    )
    To use the variadic concept in a function or class template its template
parameters are simply forwarded to the concept (as shown in the above
example). 

When no predefined variadic type trait is available the variadic concept must
use other means to determine whether its constraints are satisfied or not. In
those cases define your own variadic type traits. For illustration let's
assume we are looking for a variadic concept that can be used to verify that
the types of all the arguments that are passed to a variadic function template
are integral types. In this case there is no predefined type trait we can use,
so we have to define it ourselves. We define the concept tt(IntegralOnly) as a
variadic concept using our self-defined type trait tt(allIntegralTypes), and
thereupon use it when defining a function requiring that all of its arguments
are integral values:
    verbinsert(-s4 //concept examples/variadic.cc)

The generic type trait tt(allIntegralTypes) merely specifies that it accepts
any number of type parameters and uses specializations to handle specific
cases. One specific case is the case were no types are specified which simply
defines a tt(true static bool const) value:
    verbinsert(-s4 //generic examples/variadic.cc)

The type trait's partial specialization does the hard work: it determines
whether the first type is integral and combines that (using tt(and)) with the
tt(value) made available by the tt(struct allIntegralType) receiving the
remaining types:
    verbinsert(-s4 //partial examples/variadic.cc)

The function tt(fun) can now be called with any number of arguments. As long
as the arguments are integral types the compilation succeeds and tt(fun) can
safely do its job.