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
|
Constrained function- or class-templates can be declared as usual:
instead of the implementations semicolons are used. When declaring a function-
or class-template without constraint specifications then the function or class
template is unconstrained and won't match existing constrained overloaded
versions of such function or class templates. On the other hand,
hi(concept: declaration) concepts can+em(not) be declared. So if a concept
definition must be used in multiple source or header files then the concept
definition normally is provided in a header file of its own which is then
included by files using the concept.
Here are some simple examples illustrating how constrained
function templates are declared:
verbinsert(-s4 //functions examples/declarations.cc)
When declaring class templates their requires-clauses must precede the class
names. Also, when unconstrained class templates are available the constrained
class templates are in fact specializations and must be declared accordingly:
verbinsert(-s4 //classes examples/declarations.cc)
Multiple constraints can also be declared:
verbinsert(-s4 //multi examples/declarations.cc)
Although specializations may define different constraints (e.g., there may
also be a concept tt(Subtractable)), a tt(Data) specialization for
subtractable types might also be defined:
verb( template <Subtractable Type>
struct Data<Type>
{};)
But this is probably not what you want: when defining tt(Data<vector<int>>{}),
where tt(template<typename Type> Data) is merely declared, the compiler
complains about an em(incomplete type `struct Data<std::vector<int>>') as it
cannot use the specialization for either tt(Addable) or tt(Subtractable). So
it falls back on the generic template, but for that one no implementation is
available, and hence it's incomplete.
Defining a template requiring two types, the first being tt(Addable) and the
second template argument being unrestricted, while a specialization is defined
requiring a tt(Subtractable) type and an tt(int), then that also
does'n work as intended. In that case, the templates might be:
verbinsert(-s4 //two examples/multideclare.cc)
Here, if the first template argument isn't a subtractable type (like a
tt(vector<int>)), and the second argument em(is) an tt(int) then the compiler
simply won't use it because the 1st argument isn't a subtractable type.
Therefore it falls back to the first (generic) template definition. However,
that one doesn't work either, because the first argument also isn't
addable, and you receive complaints about tt((lh + rh)) being ill-formed.
Now, as you specified tt(int) as the template's second argument chances are
that you expected a complaint about tt((lh - rh)) being ill formed, but that
doesn't happen. In other words: using concepts still requires you to
understand what's going on. Concepts help the compiler to pinpoint reasons
for compilation failures, but in the end it's you who has to understand what
you're doing in order to grasp what the compiler is trying to tell you.
|