Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 11

 

  Главная      Manuals     Working Draft, Standard for Programming Language C++ (N4713, 2017 year)

 

Search            copyright infringement  

 

 

 

 

 

 

 

 

 

 

 

Content      ..     9      10      11      12     ..

 

 

 

Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 11

 

 

3
Each conversion in Table 13 also has an associated rank (Exact Match, Promotion, or Conversion). These are
used to rank standard conversion sequences (16.3.3.2). The rank of a conversion sequence is determined by
considering the rank of each conversion in the sequence and the rank of any reference binding (16.3.3.1.4). If
any of those has Conversion rank, the sequence has Conversion rank; otherwise, if any of those has Promotion
rank, the sequence has Promotion rank; otherwise, the sequence has Exact Match rank.
Table 13 — Conversions
Conversion
Category
Rank
Subclause
No conversions required
Identity
Lvalue-to-rvalue conversion
7.1
Array-to-pointer conversion
Lvalue Transformation
7.2
Exact Match
Function-to-pointer conversion
7.3
Qualification conversions
7.5
Qualification Adjustment
Function pointer conversion
7.13
Integral promotions
7.6
Promotion
Promotion
Floating-point promotion
7.7
Integral conversions
7.8
Floating-point conversions
7.9
Floating-integral conversions
7.10
Conversion
Conversion
Pointer conversions
7.11
Pointer-to-member conversions
7.12
Boolean conversions
7.14
16.3.3.1.2
User-defined conversion sequences
[over.ics.user]
1
A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-
defined conversion (15.3) followed by a second standard conversion sequence. If the user-defined conversion is
specified by a constructor (15.3.1), the initial standard conversion sequence converts the source type to the
type required by the argument of the constructor. If the user-defined conversion is specified by a conversion
function (15.3.2), the initial standard conversion sequence converts the source type to the implicit object
parameter of the conversion function.
2
The second standard conversion sequence converts the result of the user-defined conversion to the target type
for the sequence. Since an implicit conversion sequence is an initialization, the special rules for initialization
by user-defined conversion apply when selecting the best user-defined conversion for a user-defined conversion
sequence (see 16.3.3 and 16.3.3.1).
3
If the user-defined conversion is specified by a specialization of a conversion function template, the second
standard conversion sequence shall have exact match rank.
4
A conversion of an expression of class type to the same class type is given Exact Match rank, and a conversion
of an expression of class type to a base class of that type is given Conversion rank, in spite of the fact that a
constructor (i.e., a user-defined conversion function) is called for those cases.
16.3.3.1.3
Ellipsis conversion sequences
[over.ics.ellipsis]
1
An ellipsis conversion sequence occurs when an argument in a function call is matched with the ellipsis
parameter specification of the function called (see 8.5.1.2).
16.3.3.1.4
Reference binding
[over.ics.ref]
1
When a parameter of reference type binds directly (11.6.3) to an argument expression, the implicit conversion
sequence is the identity conversion, unless the argument expression has a type that is a derived class of the
parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion (16.3.3.1).
[ Example:
struct A {};
struct B : public A {} b;
int f(A&);
int f(B&);
int i = f(b);
// calls f(B&), an exact match, rather than f(A&), a conversion
§ 16.3.3.1.4
292
— end example ] If the parameter binds directly to the result of applying a conversion function to the argument
expression, the implicit conversion sequence is a user-defined conversion sequence (16.3.3.1.2), with the second
standard conversion sequence either an identity conversion or, if the conversion function returns an entity of
a type that is a derived class of the parameter type, a derived-to-base Conversion.
2
When a parameter of reference type is not bound directly to an argument expression, the conversion
sequence is the one required to convert the argument expression to the referenced type according to 16.3.3.1.
Conceptually, this conversion sequence corresponds to copy-initializing a temporary of the referenced type
with the argument expression. Any difference in top-level cv-qualification is subsumed by the initialization
itself and does not constitute a conversion.
3
Except for an implicit object parameter, for which see 16.3.1, a standard conversion sequence cannot be
formed if it requires binding an lvalue reference other than a reference to a non-volatile const type to
an rvalue or binding an rvalue reference to an lvalue other than a function lvalue.
[Note: This means,
for example, that a candidate function cannot be a viable function if it has a non-const lvalue reference
parameter (other than the implicit object parameter) and the corresponding argument would require a
temporary to be created to initialize the lvalue reference (see 11.6.3).
— end note ]
4
Other restrictions on binding a reference to a particular argument that are not based on the types of the
reference and the argument do not affect the formation of a standard conversion sequence, however. [ Example:
A function with an “lvalue reference to int” parameter can be a viable candidate even if the corresponding
argument is an int bit-field. The formation of implicit conversion sequences treats the int bit-field as an
int lvalue and finds an exact match with the parameter. If the function is selected by overload resolution,
the call will nonetheless be ill-formed because of the prohibition on binding a non-const lvalue reference to a
bit-field (11.6.3).
— end example ]
16.3.3.1.5
List-initialization sequence
[over.ics.list]
1
When an argument is an initializer list (11.6.4), it is not an expression and special rules apply for converting
it to a parameter type.
2
If the initializer list is a designated-initializer-list, a conversion is only possible if the parameter has an aggregate
type that can be initialized from the initializer list according to the rules for aggregate initialization (11.6.1),
in which case the implicit conversion sequence is a user-defined conversion sequence whose second standard
conversion sequence is an identity conversion.
[Note: Aggregate initialization does not require that the
members are declared in designation order. If, after overload resolution, the order does not match for the
selected overload, the initialization of the parameter will be ill-formed (11.6.4). [ Example:
struct A { int x, y; };
struct B { int y, x; };
void f(A a, int);
// #1
void f(B b, ...);
// #2
void g(A a);
// #3
void g(B b);
// #4
void h() {
f({.x = 1, .y = 2}, 0);
// OK; calls #1
f({.y = 2, .x = 1}, 0);
// error: selects #1, initialization of a fails
// due to non-matching member order (11.6.4)
g({.x = 1, .y = 2});
// error: ambiguous between #3 and #4
}
— end example ]
— end note ]
3
Otherwise, if the parameter type is an aggregate class X and the initializer list has a single element of type
cv U, where U is X or a class derived from X, the implicit conversion sequence is the one required to convert
the element to the parameter type.
4
Otherwise, if the parameter type is a character array134 and the initializer list has a single element that is an
appropriately-typed string literal (11.6.2), the implicit conversion sequence is the identity conversion.
5
Otherwise, if the parameter type is std::initializer_list<X> and all the elements of the initializer list
can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert
an element of the list to X, or if the initializer list has no elements, the identity conversion. This conversion
can be a user-defined conversion even in the context of a call to an initializer-list constructor. [ Example:
134) Since there are no parameters of array type, this will only occur as the referenced type of a reference parameter.
§ 16.3.3.1.5
293
void f(std::initializer_list<int>);
f( {} );
// OK: f(initializer_list<int>) identity conversion
f( {1,2,3} );
// OK: f(initializer_list<int>) identity conversion
f( {’a’,’b’} );
// OK: f(initializer_list<int>) integral promotion
f( {1.0} );
// error: narrowing
struct A {
A(std::initializer_list<double>);
// #1
A(std::initializer_list<complex<double>>);
// #2
A(std::initializer_list<std::string>);
// #3
};
A a{ 1.0,2.0 };
// OK, uses #1
void g(A);
g({ "foo", "bar" });
// OK, uses #3
typedef int IA[3];
void h(const IA&);
h({ 1, 2, 3 });
// OK: identity conversion
— end example ]
6
Otherwise, if the parameter type is “array of N X”, if there exists an implicit conversion sequence for each
element of the array from the corresponding element of the initializer list (or from {} if there is no such
element), the implicit conversion sequence is the worst such implicit conversion sequence.
7
Otherwise, if the parameter is a non-aggregate class X and overload resolution per 16.3.1.7 chooses a single
best constructor C of X to perform the initialization of an object of type X from the argument initializer list:
(7.1)
If C is not an initializer-list constructor and the initializer list has a single element of type cv U, where
U is X or a class derived from X, the implicit conversion sequence has Exact Match rank if U is X, or
Conversion rank if U is derived from X.
(7.2)
Otherwise, the implicit conversion sequence is a user-defined conversion sequence with the second
standard conversion sequence an identity conversion.
If multiple constructors are viable but none is better than the others, the implicit conversion sequence is
the ambiguous conversion sequence. User-defined conversions are allowed for conversion of the initializer list
elements to the constructor parameter types except as noted in 16.3.3.1. [ Example:
struct A {
A(std::initializer_list<int>);
};
void f(A);
f( {’a’, ’b’} );
// OK: f(A(std::initializer_list<int>)) user-defined conversion
struct B {
B(int, double);
};
void g(B);
g( {’a’, ’b’} );
// OK: g(B(int, double)) user-defined conversion
g( {1.0, 1.0} );
// error: narrowing
void f(B);
f( {’a’, ’b’} );
// error: ambiguous f(A) or f(B)
struct C {
C(std::string);
};
void h(C);
h({"foo"});
// OK: h(C(std::string("foo")))
struct D {
D(A, C);
};
void i(D);
i({ {1,2}, {"bar"} });
// OK: i(D(A(std::initializer_list<int>{1,2}), C(std::string("bar"))))
§ 16.3.3.1.5
294
— end example ]
8
Otherwise, if the parameter has an aggregate type which can be initialized from the initializer list according
to the rules for aggregate initialization (11.6.1), the implicit conversion sequence is a user-defined conversion
sequence with the second standard conversion sequence an identity conversion. [ Example:
struct A {
int m1;
double m2;
};
void f(A);
f( {’a’, ’b’} );
// OK: f(A(int,double)) user-defined conversion
f( {1.0} );
// error: narrowing
— end example ]
9
Otherwise, if the parameter is a reference, see 16.3.3.1.4. [Note: The rules in this subclause will apply for
initializing the underlying temporary for the reference.
— end note ] [ Example:
struct A {
int m1;
double m2;
};
void f(const A&);
f( {’a’, ’b’} );
// OK: f(A(int,double)) user-defined conversion
f( {1.0} );
// error: narrowing
void g(const double &);
g({1});
// same conversion as int to double
— end example ]
10
Otherwise, if the parameter type is not a class:
(10.1)
if the initializer list has one element that is not itself an initializer list, the implicit conversion sequence
is the one required to convert the element to the parameter type; [ Example:
void f(int);
f( {’a’} );
// OK: same conversion as char to int
f( {1.0} );
// error: narrowing
— end example ]
(10.2)
if the initializer list has no elements, the implicit conversion sequence is the identity conversion.
[ Example:
void f(int);
f( { } );
// OK: identity conversion
— end example ]
11
In all cases other than those enumerated above, no conversion is possible.
16.3.3.2
Ranking implicit conversion sequences
[over.ics.rank]
1
This subclause defines a partial ordering of implicit conversion sequences based on the relationships better
conversion sequence and better conversion. If an implicit conversion sequence S1 is defined by these rules to
be a better conversion sequence than S2, then it is also the case that S2 is a worse conversion sequence than
S1. If conversion sequence S1 is neither better than nor worse than conversion sequence S2, S1 and S2 are
said to be indistinguishable conversion sequences.
2
When comparing the basic forms of implicit conversion sequences (as defined in 16.3.3.1)
(2.1)
a standard conversion sequence (16.3.3.1.1) is a better conversion sequence than a user-defined conversion
sequence or an ellipsis conversion sequence, and
(2.2)
a user-defined conversion sequence (16.3.3.1.2) is a better conversion sequence than an ellipsis conversion
sequence (16.3.3.1.3).
3
Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of
the following rules applies:
§ 16.3.3.2
295
(3.1)
List-initialization sequence L1 is a better conversion sequence than list-initialization sequence L2 if
(3.1.1)
L1 converts to std::initializer_list<X> for some X and L2 does not, or, if not that,
(3.1.2)
L1 converts to type “array of N1 T”, L2 converts to type “array of N2 T”, and N1 is smaller than N2,
even if one of the other rules in this paragraph would otherwise apply. [ Example:
void f1(int);
// #1
void f1(std::initializer_list<long>);
// #2
void g1() { f1({42}); }
// chooses #2
void f2(std::pair<const char*, const char*>); // #3
void f2(std::initializer_list<std::string>);
// #4
void g2() { f2({"foo","bar"}); }
// chooses #4
— end example ]
(3.2)
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2
if
(3.2.1)
S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form
defined by 16.3.3.1.1, excluding any Lvalue Transformation; the identity conversion sequence is
considered to be a subsequence of any non-identity conversion sequence) or, if not that,
(3.2.2)
the rank of S1 is better than the rank of S2, or S1 and S2 have the same rank and are distinguishable
by the rules in the paragraph below, or, if not that,
(3.2.3)
S1 and S2 are reference bindings (11.6.3) and neither refers to an implicit object parameter of a
non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to
an rvalue and S2 binds an lvalue reference [ Example:
int i;
int f1();
int&& f2();
int g(const int&);
int g(const int&&);
int j = g(i);
// calls g(const int&)
int k = g(f1());
// calls g(const int&&)
int l = g(f2());
// calls g(const int&&)
struct A {
A& operator<<(int);
void p() &;
void p() &&;
};
A& operator<<(A&&, char);
A() << 1;
// calls A::operator<<(int)
A() << ’c’;
// calls operator<<(A&&, char)
A a;
a << 1;
// calls A::operator<<(int)
a << ’c’;
// calls A::operator<<(int)
A().p();
// calls A::p()&&
a.p();
// calls A::p()&
— end example ] or, if not that,
(3.2.4)
S1 and S2 are reference bindings (11.6.3) and S1 binds an lvalue reference to a function lvalue and
S2 binds an rvalue reference to a function lvalue [ Example:
int f(void(&)());
// #1
int f(void(&&)());
// #2
void g();
int i1 = f(g);
// calls #1
— end example ] or, if not that,
(3.2.5)
S1 and S2 differ only in their qualification conversion and yield similar types T1 and T2 (7.5),
respectively, and the cv-qualification signature of type T1 is a proper subset of the cv-qualification
signature of type T2 [ Example:
int f(const volatile int *);
§
16.3.3.2
296
int f(const int *);
int i;
int j = f(&i);
// calls f(const int*)
— end example ] or, if not that,
(3.2.6)
S1 and S2 are reference bindings (11.6.3), and the types to which the references refer are the same
type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers
is more cv-qualified than the type to which the reference initialized by S1 refers. [ Example:
int f(const int &);
int f(int &);
int g(const int &);
int g(int);
int i;
int j = f(i);
// calls f(int &)
int k = g(i);
// ambiguous
struct X {
void f() const;
void f();
};
void g(const X& a, X b) {
a.f();
// calls X::f() const
b.f();
// calls X::f()
}
— end example ]
(3.3)
User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion
sequence U2 if they contain the same user-defined conversion function or constructor or they initialize
the same class in an aggregate initialization and in either case the second standard conversion sequence
of U1 is better than the second standard conversion sequence of U2. [ Example:
struct A {
operator short();
} a;
int f(int);
int f(float);
int i = f(a);
// calls f(int), because short → int is
// better than short → float.
— end example ]
4
Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a
Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank
are indistinguishable unless one of the following rules applies:
(4.1)
A conversion that does not convert a pointer, a pointer to member, or std::nullptr_t to bool is
better than one that does.
(4.2)
A conversion that promotes an enumeration whose underlying type is fixed to its underlying type is
better than one that promotes to the promoted underlying type, if the two are different.
(4.3)
If class B is derived directly or indirectly from class A, conversion of B* to A* is better than conversion
of B* to void*, and conversion of A* to void* is better than conversion of B* to void*.
(4.4)
If class B is derived directly or indirectly from class A and class C is derived directly or indirectly from B,
(4.4.1)
conversion of C* to B* is better than conversion of C* to A*, [ Example:
struct A {};
struct B : public A {};
struct C : public B {};
C* pc;
int f(A*);
int f(B*);
int i = f(pc);
// calls f(B*)
— end example ]
§ 16.3.3.2
297
(4.4.2)
binding of an expression of type C to a reference to type B is better than binding an expression of
type C to a reference to type A,
(4.4.3)
conversion of A::* to B::* is better than conversion of A::* to C::*,
(4.4.4)
conversion of C to B is better than conversion of C to A,
(4.4.5)
conversion of B* to A* is better than conversion of C* to A*,
(4.4.6)
binding of an expression of type B to a reference to type A is better than binding an expression of
type C to a reference to type A,
(4.4.7)
conversion of B::* to C::* is better than conversion of A::* to C::*, and
(4.4.8)
conversion of B to A is better than conversion of C to A.
[ Note: Compared conversion sequences will have different source types only in the context of comparing
the second standard conversion sequence of an initialization by user-defined conversion (see 16.3.3); in
all other contexts, the source types will be the same and the target types will be different.
— end note ]
16.4
Address of overloaded function
[over.over]
1
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a
pointer to function or a pointer to member function for a specific function from the overload set. A function
template name is considered to name a set of overloaded functions in such contexts. A function with type F
is selected for the function type FT of the target type required in the context if F (after possibly applying the
function pointer conversion (7.13)) is identical to FT. [ Note: That is, the class of which the function is a
member is ignored when matching a pointer-to-member-function type.
— end note ] The target can be
(1.1)
an object or reference being initialized (11.6, 11.6.3, 11.6.4),
(1.2)
the left side of an assignment (8.5.18),
(1.3)
a parameter of a function (8.5.1.2),
(1.4)
a parameter of a user-defined operator (16.5),
(1.5)
the return value of a function, operator function, or conversion (9.6.3),
(1.6)
an explicit type conversion (8.5.1.3, 8.5.1.9, 8.5.3), or
(1.7)
a non-type template-parameter (17.3.2).
The overloaded function name can be preceded by the & operator. An overloaded function name shall not
be used without arguments in contexts other than those listed. [Note: Any redundant set of parentheses
surrounding the overloaded function name is ignored (8.4).
— end note ]
2
If the name is a function template, template argument deduction is done (17.9.2.2), and if the argument
deduction succeeds, the resulting template argument list is used to generate a single function template
specialization, which is added to the set of overloaded functions considered. [Note: As described in 17.9.1,
if deduction fails and the function template name is followed by an explicit template argument list, the
template-id is then examined to see whether it identifies a single function template specialization. If it does,
the template-id is considered to be an lvalue for that function template specialization. The target type is not
used in that determination.
— end note ]
3
Non-member functions and static member functions match targets of function pointer type or reference to
function type. Non-static member functions match targets of pointer-to-member-function type. If a non-static
member function is selected, the reference to the overloaded function name is required to have the form of a
pointer to member as described in 8.5.2.1.
4
All functions with associated constraints that are not satisfied (17.4.2) are eliminated from the set of selected
functions. If more than one function in the set remains, all function template specializations in the set are
eliminated if the set also contains a function that is not a function template specialization. Any given non-
template function F0 is eliminated if the set contains a second non-template function that is more constrained
than F0 according to the partial ordering rules of 17.4.4. Any given function template specialization F1 is
eliminated if the set contains a second function template specialization whose function template is more
specialized than the function template of F1 according to the partial ordering rules of 17.6.6.2. After such
eliminations, if any, there shall remain exactly one selected function.
5
[ Example:
int f(double);
§ 16.4
298
int f(int);
int (*pfd)(double) = &f;
// selects f(double)
int (*pfi)(int) = &f;
// selects f(int)
int (*pfe)(...) = &f;
// error: type mismatch
int (&rfi)(int) = f;
// selects f(int)
int (&rfd)(double) = f;
// selects f(double)
void g() {
(int (*)(int))&f;
// cast expression as selector
}
The initialization of pfe is ill-formed because no f() with type int(...) has been declared, and not because
of any ambiguity. For another example,
struct X {
int f(int);
static int f(long);
};
int (X::*p1)(int)
= &X::f;
// OK
int
(*p2)(int)
= &X::f;
// error: mismatch
int
(*p3)(long) = &X::f;
// OK
int (X::*p4)(long) = &X::f;
// error: mismatch
int (X::*p5)(int)
= &(X::f);
// error: wrong syntax for
// pointer to member
int
(*p6)(long) = &(X::f);
// OK
— end example ]
6
[ Note: If f() and g() are both overloaded functions, the cross product of possibilities must be considered to
resolve f(&g), or the equivalent expression f(g).
— end note ]
7
[ Note: Even if B is a public base of D, we have
D* f();
B* (*p1)() = &f;
// error
void g(D*);
void (*p2)(B*) = &g;
// error
— end note ]
16.5
Overloaded operators
[over.oper]
1
A function declaration having one of the following operator-function-ids as its name declares an operator
function. A function template declaration having one of the following operator-function-ids as its name
declares an operator function template. A specialization of an operator function template is also an operator
function. An operator function is said to implement the operator named in its operator-function-id.
operator-function-id:
operator operator
operator: one of
new
delete new[]
delete[] ( )
[]
->
->*
~
!
+
-
/
%
^
&
|
=
+=
-=
*=
/=
%=
^=
&=
|=
==
!=
<
>
<=
>=
<=>
&&
||
<<
>>
<<=
>>=
++
--
,
[Note: The last two operators are function call (8.5.1.2) and subscripting (8.5.1.1). The operators new[],
delete[], (), and [] are formed from more than one token. — end note ]
2
Both the unary and binary forms of
+
-
&
can be overloaded.
3
The following operators cannot be overloaded:
.*
::
?:
§ 16.5
299
nor can the preprocessing symbols # and ## (Clause 19).
4
Operator functions are usually not called directly; instead they are invoked to evaluate the operators they
implement (16.5.1 - 16.5.7). They can be explicitly called, however, using the operator-function-id as the
name of the function in the function call syntax (8.5.1.2). [ Example:
complex z = a.operator+(b);
// complex z = a+b;
void* p = operator new(sizeof(int)*n);
— end example ]
5
The allocation and deallocation functions, operator new, operator new[], operator delete and operator
delete[], are described completely in 6.6.4.4. The attributes and restrictions found in the rest of this
subclause do not apply to them unless explicitly stated in 6.6.4.4.
6
An operator function shall either be a non-static member function or be a non-member function that has
at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an
enumeration. It is not possible to change the precedence, grouping, or number of operands of operators.
The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed for
specific class and enumeration types by defining operator functions that implement these operators. Operator
functions are inherited in the same manner as other base class functions.
7
The identities among certain predefined operators applied to basic types (for example, ++a ≡ a+=1) need not
hold for operator functions. Some predefined operators, such as +=, require an operand to be an lvalue when
applied to basic types; this is not required by operator functions.
8
An operator function cannot have default arguments (11.3.6), except where explicitly stated below. Operator
functions cannot have more or fewer parameters than the number required for the corresponding operator, as
described in the rest of this subclause.
9
Operators not mentioned explicitly in subclauses 16.5.3 through 16.5.7 act as ordinary unary and binary
operators obeying the rules of 16.5.1 or 16.5.2.
16.5.1
Unary operators
[over.unary]
1
A prefix unary operator shall be implemented by a non-static member function (12.2.1) with no parameters
or a non-member function with one parameter. Thus, for any prefix unary operator @, @x can be interpreted
as either x.operator@() or operator@(x). If both forms of the operator function have been declared, the
rules in 16.3.1.2 determine which, if any, interpretation is used. See 16.5.7 for an explanation of the postfix
unary operators ++ and --.
2
The unary and binary forms of the same operator are considered to have the same name. [ Note: Consequently,
a unary operator can hide a binary operator from an enclosing scope, and vice versa.
— end note ]
16.5.2
Binary operators
[over.binary]
1
A binary operator shall be implemented either by a non-static member function (12.2.1) with one parameter
or by a non-member function with two parameters. Thus, for any binary operator @, x@y can be interpreted
as either x.operator@(y) or operator@(x,y). If both forms of the operator function have been declared,
the rules in 16.3.1.2 determine which, if any, interpretation is used.
16.5.3
Assignment
[over.ass]
1
An assignment operator shall be implemented by a non-static member function with exactly one parameter.
Because a copy assignment operator operator= is implicitly declared for a class if not declared by the
user (15.8), a base class assignment operator is always hidden by the copy assignment operator of the derived
class.
2
Any assignment operator, even the copy and move assignment operators, can be virtual. [ Note: For a derived
class D with a base class B for which a virtual copy/move assignment has been declared, the copy/move
assignment operator in D does not override B’s virtual copy/move assignment operator. [ Example:
struct B {
virtual int operator= (int);
virtual B& operator= (const B&);
};
struct D : B {
virtual int operator= (int);
§ 16.5.3
300
virtual D& operator= (const B&);
};
D dobj1;
D dobj2;
B* bptr = &dobj1;
void f() {
bptr->operator=(99);
// calls D::operator=(int)
*bptr = 99;
// ditto
bptr->operator=(dobj2);
// calls D::operator=(const B&)
*bptr = dobj2;
// ditto
dobj1 = dobj2;
// calls implicitly-declared D::operator=(const D&)
}
— end example ]
— end note ]
16.5.4
Function call
[over.call]
1
operator() shall be a non-static member function with an arbitrary number of parameters. It can have
default arguments. It implements the function call syntax
postfix-expression ( expression-listopt )
where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the
parameter list of an operator() member function of the class. Thus, a call x(arg1,...) is interpreted as
x.operator()(arg1, ...) for a class object x of type T if T::operator()(T1, T2, T3) exists and if the
operator is selected as the best match function by the overload resolution mechanism (16.3.3).
16.5.5
Subscripting
[over.sub]
1
operator[] shall be a non-static member function with exactly one parameter. It implements the subscripting
syntax
postfix-expression [ expr-or-braced-init-list ]
Thus, a subscripting expression x[y] is interpreted as x.operator[](y) for a class object x of type T if
T::operator[](T1) exists and if the operator is selected as the best match function by the overload resolution
mechanism (16.3.3). [ Example:
struct X {
Z operator[](std::initializer_list<int>);
};
X x;
x[{1,2,3}] = 7;
// OK: meaning x.operator[]({1,2,3})
int a[10];
a[{1,2,3}] = 7;
// error: built-in subscript operator
— end example ]
16.5.6
Class member access
[over.ref]
1
operator-> shall be a non-static member function taking no parameters. It implements the class member
access syntax that uses ->.
postfix-expression -> templateopt id-expression
postfix-expression -> pseudo-destructor-name
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->()
exists and if the operator is selected as the best match function by the overload resolution mechanism (16.3).
16.5.7
Increment and decrement
[over.inc]
1
The user-defined function called operator++ implements the prefix and postfix ++ operator. If this function
is a non-static member function with no parameters, or a non-member function with one parameter, it defines
the prefix increment operator ++ for objects of that type. If the function is a non-static member function
with one parameter (which shall be of type int) or a non-member function with two parameters (the second
of which shall be of type int), it defines the postfix increment operator ++ for objects of that type. When
§ 16.5.7
301
the postfix increment is called as a result of using the ++ operator, the int argument will have value zero.135
[ Example:
struct X {
X& operator++();
// prefix ++a
X
operator++(int);
// postfix a++
};
struct Y { };
Y& operator++(Y&);
// prefix ++b
Y
operator++(Y&, int);
// postfix b++
void f(X a, Y b) {
++a;
// a.operator++();
a++;
// a.operator++(0);
++b;
// operator++(b);
b++;
// operator++(b, 0);
a.operator++();
// explicit call: like ++a;
a.operator++(0);
// explicit call: like a++;
operator++(b);
// explicit call: like ++b;
operator++(b, 0);
// explicit call: like b++;
}
— end example ]
2
The prefix and postfix decrement operators -- are handled analogously.
16.5.8
User-defined literals
[over.literal]
literal-operator-id:
operator string-literal identifier
operator user-defined-string-literal
1
The string-literal or user-defined-string-literal in a literal-operator-id shall have no encoding-prefix and shall
contain no characters other than the implicit terminating ’\0’. The ud-suffix of the user-defined-string-literal
or the identifier in a literal-operator-id is called a literal suffix identifier. Some literal suffix identifiers are
reserved for future standardization; see 20.5.4.3.5. A declaration whose literal-operator-id uses such a literal
suffix identifier is ill-formed, no diagnostic required.
2
A declaration whose declarator-id is a literal-operator-id shall be a declaration of a namespace-scope function
or function template (it could be a friend function (14.3)), an explicit instantiation or specialization of a
function template, or a using-declaration (10.3.3). A function declared with a literal-operator-id is a literal
operator. A function template declared with a literal-operator-id is a literal operator template.
3
The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the
following:
const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t
If a parameter has a default argument (11.3.6), the program is ill-formed.
4
A raw literal operator is a literal operator with a single parameter whose type is const char*.
135) Calling operator++ explicitly, as in expressions like a.operator++(2), has no special properties: The argument to operator++
is 2.
§ 16.5.8
302
5
The declaration of a literal operator template shall have an empty parameter-declaration-clause and its
template-parameter-list shall have a single template-parameter that is a non-type template parameter pack
(17.6.3) with element type char.
6
Literal operators and literal operator templates shall not have C language linkage.
7
[Note: Literal operators and literal operator templates are usually invoked implicitly through user-defined
literals (5.13.8). However, except for the constraints described above, they are ordinary namespace-scope
functions and function templates. In particular, they are looked up like ordinary functions and function
templates and they follow the same overload resolution rules. Also, they can be declared inline or constexpr,
they may have internal or external linkage, they can be called explicitly, their addresses can be taken, etc.
— end note ]
8
[ Example:
void operator "" _km(long double);
// OK
string operator "" _i18n(const char*, std::size_t); // OK
template <char...> double operator "" _\u03C0();
// OK: UCN for lowercase pi
float operator ""_e(const char*);
// OK
float operator ""E(const char*);
// error: reserved literal suffix (20.5.4.3.5, 5.13.8)
double operator""_Bq(long double);
// OK: does not use the reserved identifier _Bq (5.10)
double operator"" _Bq(long double);
// uses the reserved identifier _Bq (5.10)
float operator " " B(const char*);
// error: non-empty string-literal
string operator "" 5X(const char*, std::size_t);
// error: invalid literal suffix identifier
double operator "" _miles(double);
// error: invalid parameter-declaration-clause
template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause
extern "C" void operator "" _m(long double);
// error: C language linkage
— end example ]
16.6
Built-in operators
[over.built]
1
The candidate operator functions that represent the built-in operators defined in 8.5 are specified in this
subclause. These candidate functions participate in the operator overload resolution process as described
in 16.3.1.2 and are used for no other purpose. [Note: Because built-in operators take only operands with
non-class type, and operator overload resolution occurs only when an operand expression originally has class
or enumeration type, operator overload resolution can resolve to a built-in operator only when an operand
has a class type that has a user-defined conversion to a non-class type appropriate for the operator, or when
an operand has an enumeration type that can be converted to a type appropriate for the operator. Also note
that some of the candidate operator functions given in this subclause are more permissive than the built-in
operators themselves. As described in 16.3.1.2, after a built-in operator is selected by overload resolution
the expression is subject to the requirements for the built-in operator given in 8.5, and therefore to any
additional semantic constraints given there. If there is a user-written candidate with the same name and
parameter types as a built-in candidate operator function, the built-in operator function is hidden and is not
included in the set of candidate functions.
— end note ]
2
In this subclause, the term promoted integral type is used to refer to those integral types which are preserved
by integral promotion (7.6) (including e.g. int and long but excluding e.g. char). Similarly, the term
promoted arithmetic type refers to floating types plus promoted integral types. [ Note: In all cases where a
promoted integral type or promoted arithmetic type is required, an operand of enumeration type will be
acceptable by way of the integral promotions.
— end note ]
3
In the remainder of this subclause, vq represents either volatile or no cv-qualifier.
4
For every pair (T , vq), where T is an arithmetic type other than bool, there exist candidate operator functions
of the form
vq T & operator++(vq T &);
T operator++(vq T &, int);
5
For every pair (T , vq), where T is an arithmetic type other than bool, there exist candidate operator functions
of the form
vq T & operator--(vq T &);
T operator--(vq T &, int);
6
For every pair (T , vq), where T is a cv-qualified or cv-unqualified object type, there exist candidate operator
functions of the form
§ 16.6
303
T *vq & operator++(T *vq &);
T *vq & operator--(T *vq &);
T*
operator++(T *vq &, int);
T*
operator--(T *vq &, int);
7
For every cv-qualified or cv-unqualified object type T , there exist candidate operator functions of the form
T&
operator*(T *);
8
For every function type T that does not have cv-qualifiers or a ref-qualifier, there exist candidate operator
functions of the form
T&
operator*(T *);
9
For every type T there exist candidate operator functions of the form
T*
operator+(T *);
10
For every promoted arithmetic type T , there exist candidate operator functions of the form
T operator+(T );
T operator-(T );
11
For every promoted integral type T , there exist candidate operator functions of the form
T operator~(T );
12
For every quintuple (C1 , C2 , T , cv1, cv2 ), where C2 is a class type, C1 is the same type as C2 or is a derived
class of C2 , and T is an object type or a function type, there exist candidate operator functions of the form
cv12 T & operator->*(cv1 C1 *, cv2 T C2 ::*);
where cv12 is the union of cv1 and cv2. The return type is shown for exposition only; see 8.5.4 for the
determination of the operator’s result type.
13
For every pair of promoted arithmetic types L and R , there exist candidate operator functions of the form
LR
operator*(L , R );
LR
operator/(L , R );
LR
operator+(L , R );
LR
operator-(L , R );
bool
operator<(L , R );
bool
operator>(L , R );
bool
operator<=(L , R );
bool
operator>=(L , R );
bool
operator==(L , R );
bool
operator!=(L , R );
where LR is the result of the usual arithmetic conversions (8.3) between types L and R .
14
For every integral type T there exists a candidate operator function of the form
std::strong_ordering operator<=>(T , T );
15
For every pair of floating-point types L and R , there exists a candidate operator function of the form
std::partial_ordering operator<=>(L , R );
16
For every cv-qualified or cv-unqualified object type T there exist candidate operator functions of the form
T*
operator+(T *, std::ptrdiff_t);
T&
operator[](T *, std::ptrdiff_t);
T*
operator-(T *, std::ptrdiff_t);
T*
operator+(std::ptrdiff_t, T *);
T&
operator[](std::ptrdiff_t, T *);
17
For every T , where T is a pointer to object type, there exist candidate operator functions of the form
std::ptrdiff_t operator-(T , T );
18
For every T , where T is an enumeration type or a pointer type, there exist candidate operator functions of
the form
bool
operator<(T , T );
bool
operator>(T , T );
bool
operator<=(T , T );
bool
operator>=(T , T );
bool
operator==(T , T );
§ 16.6
304
bool
operator!=(T , T );
R
operator<=>(T , T );
where R is the result type specified in 8.5.8.
19
For every T , where T is a pointer-to-member type or std::nullptr_t, there exist candidate operator
functions of the form
bool
operator==(T , T );
bool
operator!=(T , T );
std::strong_equality operator<=>(T , T );
20
For every pair of promoted integral types L and R , there exist candidate operator functions of the form
LR
operator%(L , R );
LR
operator&(L , R );
LR
operator^(L , R );
LR
operator|(L , R );
L
operator<<(L , R );
L
operator>>(L , R );
where LR is the result of the usual arithmetic conversions (8.3) between types L and R .
21
For every triple (L , vq, R ), where L is an arithmetic type, and R is a promoted arithmetic type, there exist
candidate operator functions of the form
vq L & operator=(vq L &, R );
vq L & operator*=(vq L &, R );
vq L & operator/=(vq L &, R );
vq L & operator+=(vq L &, R );
vq L & operator-=(vq L &, R );
22
For every pair (T , vq), where T is any type, there exist candidate operator functions of the form
T *vq & operator=(T *vq &, T *);
23
For every pair (T , vq), where T is an enumeration or pointer-to-member type, there exist candidate operator
functions of the form
vq T & operator=(vq T &, T );
24
For every pair (T , vq), where T is a cv-qualified or cv-unqualified object type, there exist candidate operator
functions of the form
T *vq & operator+=(T *vq &, std::ptrdiff_t);
T *vq & operator-=(T *vq &, std::ptrdiff_t);
25
For every triple (L , vq, R ), where L is an integral type, and R is a promoted integral type, there exist
candidate operator functions of the form
vq L & operator%=(vq L &, R );
vq L & operator<<=(vq L &, R );
vq L & operator>>=(vq L &, R );
vq L & operator&=(vq L &, R );
vq L & operator^=(vq L &, R );
vq L & operator|=(vq L &, R );
26
There also exist candidate operator functions of the form
bool
operator!(bool);
bool
operator&&(bool, bool);
bool
operator||(bool, bool);
27
For every pair of promoted arithmetic types L and R , there exist candidate operator functions of the form
LR
operator?:(bool, L , R );
where LR is the result of the usual arithmetic conversions (8.3) between types L and R . [Note: As with all
these descriptions of candidate functions, this declaration serves only to describe the built-in operator for
purposes of overload resolution. The operator “?:” cannot be overloaded.
— end note ]
28
For every type T , where T is a pointer, pointer-to-member, or scoped enumeration type, there exist candidate
operator functions of the form
T
operator?:(bool, T , T );
§ 16.6
305
17
Templates
[temp]
1
A template defines a family of classes, functions, or variables, an alias for a family of types, or a concept.
template-declaration:
template-head declaration
template-head concept-definition
template-head:
template < template-parameter-list > requires-clauseopt
template-parameter-list:
template-parameter
template-parameter-list , template-parameter
requires-clause:
requires constraint-logical-or-expression
constraint-logical-or-expression:
constraint-logical-and-expression
constraint-logical-or-expression || constraint-logical-and-expression
constraint-logical-and-expression:
primary-expression
constraint-logical-and-expression && primary-expression
concept-definition:
concept concept-name = constraint-expression ;
concept-name:
identifier
[Note: The > token following the template-parameter-list of a template-declaration may be the product of
replacing a >> token by two consecutive > tokens (17.2). — end note ]
2
The declaration in a template-declaration (if any) shall
(2.1)
declare or define a function, a class, or a variable, or
(2.2)
define a member function, a member class, a member enumeration, or a static data member of a class
template or of a class nested within a class template, or
(2.3)
define a member template of a class or class template, or
(2.4)
be a deduction-guide, or
(2.5)
be an alias-declaration.
3
A template-declaration is a declaration. A template-declaration is also a definition if its template-head is
followed by either a concept-definition or a declaration that defines a function, a class, a variable, or a static
data member. A declaration introduced by a template declaration of a variable is a variable template. A
variable template at class scope is a static data member template.
[ Example:
template<class T>
constexpr T pi = T(3.1415926535897932385L);
template<class T>
T circular_area(T r) {
return pi<T> * r * r;
}
struct matrix_constants {
template<class T>
using pauli = hermitian_matrix<T, 2>;
template<class T>
constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } };
template<class T>
constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } };
Templates
306
template<class T>
constexpr pauli<T> sigma3 = { { 1, 0 }, { 0, -1 } };
};
— end example ]
4
A template-declaration can appear only as a namespace scope or class scope declaration. In a function
template declaration, the last component of the declarator-id shall not be a template-id. [Note: That last
component may be an identifier, an operator-function-id, a conversion-function-id, or a literal-operator-id.
In a class template declaration, if the class name is a simple-template-id, the declaration declares a class
template partial specialization (17.6.5).
— end note ]
5
In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the
declaration shall contain at most one declarator. When such a declaration is used to declare a class template,
no declarator is permitted.
6
A template name has linkage (6.5). Specializations (explicit or implicit) of a template that has internal
linkage are distinct from all specializations in other translation units. A template, a template explicit
specialization (17.8.3), and a class template partial specialization shall not have C linkage. Use of a
linkage specification other than "C" or "C++" with any of these constructs is conditionally-supported, with
implementation-defined semantics. Template definitions shall obey the one-definition rule (6.2).
[Note:
Default arguments for function templates and for member functions of class templates are considered
definitions for the purpose of template instantiation (17.6) and must also obey the one-definition rule.
— end
note ]
7
A class template shall not have the same name as any other template, class, function, variable, enumeration,
enumerator, namespace, or type in the same scope (6.3), except as specified in 17.6.5. Except that a function
template can be overloaded either by non-template functions (11.3.5) with the same name or by other function
templates with the same name (17.9.3), a template name declared in namespace scope or in class scope shall
be unique in that scope.
8
A templated entity is
(8.1)
a template,
(8.2)
an entity defined (6.1) or created (15.2) in a templated entity,
(8.3)
a member of a templated entity,
(8.4)
an enumerator for an enumeration that is a templated entity, or
(8.5)
the closure type of a lambda-expression (8.4.5.1) appearing in the declaration of a templated entity.
[ Note: A local class, a local variable, or a friend function defined in a templated entity is a templated entity.
— end note ]
9
A template-declaration is written in terms of its template parameters. The optional requires-clause following
a template-parameter-list allows the specification of constraints (17.4.2) on template arguments (17.3). The
requires-clause introduces the constraint-expression that results from interpreting the constraint-logical-or-
expression as a constraint-expression. The constraint-logical-or-expression of a requires-clause is an unevaluated
operand (Clause 8). [ Note: The expression in a requires-clause uses a restricted grammar to avoid ambiguities.
Parentheses can be used to specify arbitrary expressions in a requires-clause. [ Example:
template<int N> requires N == sizeof new unsigned short
int f();
// error: parentheses required around == expression
— end example ]
— end note ]
10
A function template, member function of a class template, variable template, or static data member of a
class template shall be defined in every translation unit in which it is implicitly instantiated (17.8.1) unless
the corresponding specialization is explicitly instantiated (17.8.2) in some translation unit; no diagnostic is
required.
17.1
Template parameters
[temp.param]
1
The syntax for template-parameter s is:
template-parameter:
type-parameter
parameter-declaration
constrained-parameter
§ 17.1
307
type-parameter:
type-parameter-key ...opt identifieropt
type-parameter-key identifieropt = type-id
template-head type-parameter-key ...opt identifieropt
template-head type-parameter-key identifieropt = id-expression
type-parameter-key:
class
typename
constrained-parameter:
qualified-concept-name ... identifieropt
qualified-concept-name identifieropt default-template-argumentopt
qualified-concept-name:
nested-name-specifieropt concept-name
nested-name-specifieropt partial-concept-id
partial-concept-id:
concept-name < template-argument-listopt >
default-template-argument:
= type-id
= id-expression
= initializer-clause
[ Note: The > token following the template-parameter-list of a type-parameter may be the product of replacing
a >> token by two consecutive > tokens (17.2). — end note ]
2
There is no semantic difference between class and typename in a type-parameter-key. typename followed by
an unqualified-id names a template type parameter. typename followed by a qualified-id denotes the type in
a non-type136 parameter-declaration. A template-parameter of the form class identifier is a type-parameter.
[ Example:
class T { /* ... */ };
int i;
template<class T, T i> void f(T t) {
T t1 = i;
// template-parameters T and i
::T t2 = ::i;
// global namespace members T and i
}
Here, the template f has a type-parameter called T, rather than an unnamed non-type template-parameter of
class T.
— end example ] A storage class shall not be specified in a template-parameter declaration. Types
shall not be defined in a template-parameter declaration.
3
A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if
declared without template) or template-name (if declared with template) in the scope of the template
declaration. [ Note: A template argument may be a class template or alias template. For example,
template<class T> class myarray { /* ... */ };
template<class K, class V, template<class T> class C = myarray>
class Map {
C<K> key;
C<V> value;
};
— end note ]
4
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
(4.1)
integral or enumeration type,
(4.2)
pointer to object or pointer to function,
(4.3)
lvalue reference to object or lvalue reference to function,
(4.4)
pointer to member,
136) Since template template-parameter s and template template-arguments are treated as types for descriptive purposes, the
terms non-type parameter and non-type argument are used to refer to non-type, non-template parameters and arguments.
§ 17.1
308
(4.5)
std::nullptr_t, or
(4.6)
a type that contains a placeholder type (10.1.7.4).
5
[Note: Other types are disallowed either explicitly below or implicitly by the rules governing the form of
template-arguments (17.3).
— end note ] The top-level cv-qualifier s on the template-parameter are ignored
when determining its type.
6
A non-type non-reference template-parameter is a prvalue. It shall not be assigned to or in any other way
have its value changed. A non-type non-reference template-parameter cannot have its address taken. When a
non-type non-reference template-parameter is used as an initializer for a reference, a temporary is always
used. [ Example:
template<const X& x, int i> void f() {
i++;
// error: change of template-parameter value
&x;
// OK
&i;
// error: address of non-reference template-parameter
int& ri = i;
// error: non-const reference bound to temporary
const int& cri = i;
// OK: const reference bound to temporary
}
— end example ]
7
A non-type template-parameter shall not be declared to have floating-point, class, or void type. [ Example:
template<double d> class X;
// error
template<double* pd> class Y;
// OK
template<double& rd> class Z;
// OK
— end example ]
8
A non-type template-parameter of type “array of T” or of function type T is adjusted to be of type “pointer
to T”. [ Example:
template<int* a> struct R { /* ... */ };
template<int b[5]> struct S { /* ... */ };
int p;
R<&p> w;
// OK
S<&p> x;
// OK due to parameter adjustment
int v[5];
R<v> y;
// OK due to implicit argument conversion
S<v> z;
// OK due to both adjustment and conversion
— end example ]
9
A partial-concept-id is a concept-name followed by a sequence of template-arguments. These template
arguments are used to form a constraint-expression as described below.
10
A constrained-parameter declares a template parameter whose kind (type, non-type, template) and type
match that of the prototype parameter (17.6.8) of the concept designated by the qualified-concept-name
in the constrained-parameter. Let X be the prototype parameter of the designated concept. The declared
template parameter is determined by the kind of X (type, non-type, template) and the optional ellipsis in the
constrained-parameter as follows.
(10.1)
If X is a type template-parameter, the declared parameter is a type template-parameter.
(10.2)
If X is a non-type template-parameter, the declared parameter is a non-type template-parameter having
the same type as X.
(10.3)
If X is a template template-parameter, the declared parameter is a template template-parameter having
the same template-parameter-list as X, excluding default template arguments.
(10.4)
If the qualified-concept-name is followed by an ellipsis, then the declared parameter is a template
parameter pack (17.6.3).
[ Example:
template<typename T> concept C1 = true;
template<template<typename> class X> concept C2 = true;
template<int N> concept C3 = true;
template<typename... Ts> concept C4 = true;
§ 17.1
309
template<char... Cs> concept C5 = true;
template<C1 T> void f1();
// OK, T is a type template-parameter
template<C2 X> void f2();
// OK, X is a template with one type-parameter
template<C3 N> void f3();
// OK, N has type int
template<C4... Ts> void f4();
// OK, Ts is a template parameter pack of types
template<C4 T> void f5();
// OK, T is a type template-parameter
template<C5... Cs> void f6();
// OK, Cs is a template parameter pack of chars
— end example ]
11
A constrained-parameter introduces a constraint-expression (17.4.2). The expression is derived from the
qualified-concept-name Q in the constrained-parameter, its designated concept C, and the declared template
parameter P.
(11.1)
First, a template argument A is formed from P. If P declares a template parameter pack (17.6.3) and C
is a variadic concept (17.6.8), then A is the pack expansion P
Otherwise, A is the id-expression P.
(11.2)
Then, an id-expression E is formed as follows. If Q is a concept-name, then E is C<A>. Otherwise, Q is a
partial-concept-id of the form C<A1, A2, ..., An>, and E is C<A, A1, A2, ..., An>.
(11.3)
Finally, if P declares a template parameter pack and C is not a variadic concept, E is adjusted to be the
fold-expression (E && ...) (8.4.6).
E is the introduced constraint-expression. [ Example:
template<typename T> concept C1 = true;
template<typename... Ts> concept C2 = true;
template<typename T, typename U> concept C3 = true;
template<C1 T> struct s1;
// associates C1<T>
template<C1... T> struct s2;
// associates (C1<T> && ...)
template<C2... T> struct s3;
// associates C2<T...>
template<C3<int> T> struct s4;
// associates C3<T, int>
— end example ]
12
A default template-argument is a template-argument (17.3) specified after = in a template-parameter. A default
template-argument may be specified for any kind of template-parameter (type, non-type, template) that is not
a template parameter pack (17.6.3). A default template-argument may be specified in a template declaration.
A default template-argument shall not be specified in the template-parameter-lists of the definition of a
member of a class template that appears outside of the member’s class. A default template-argument shall
not be specified in a friend class template declaration. If a friend function template declaration specifies a
default template-argument, that declaration shall be a definition and shall be the only declaration of the
function template in the translation unit.
13
The default template-argument of a constrained-parameter shall match the kind (type, non-type, template) of
the declared template parameter. [ Example:
template<typename T> concept C1 = true;
template<int N> concept C2 = true;
template<template<typename> class X> concept C3 = true;
template<typename T> struct S0;
template<C1 T = int> struct S1; // OK
template<C2 N = 0> struct S2;
// OK
template<C3 X = S0> struct S3;
// OK
template<C1 T = 0> struct S4;
// error: default argument is not a type
— end example ]
14
The set of default template-arguments available for use is obtained by merging the default arguments from
all prior declarations of the template in the same way default function arguments are (11.3.6). [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
§ 17.1
310
— end example ]
15
If a template-parameter of a class template, variable template, or alias template has a default template-
argument, each subsequent template-parameter shall either have a default template-argument supplied or be a
template parameter pack. If a template-parameter of a primary class template, primary variable template, or
alias template is a template parameter pack, it shall be the last template-parameter. A template parameter
pack of a function template shall not be followed by another template parameter unless that template
parameter can be deduced from the parameter-type-list (11.3.5) of the function template or has a default
argument (17.9.2). A template parameter of a deduction guide template (17.10) that does not have a default
argument shall be deducible from the parameter-type-list of the deduction guide template. [ Example:
template<class T1 = int, class T2> class B;
// error
// U can be neither deduced from the parameter-type-list nor specified
template<class... T, class... U> void f() { }
// error
template<class... T, class U> void g() { }
// error
— end example ]
16
A template-parameter shall not be given default arguments by two different declarations in the same scope.
[ Example:
template<class T = int> class X;
template<class T = int> class X { /* ... */ };
// error
— end example ]
17
When parsing a default template-argument for a non-type template-parameter, the first non-nested > is taken
as the end of the template-parameter-list rather than a greater-than operator. [ Example:
template<int i = 3 > 4 >
// syntax error
class X { /* ... */ };
template<int i = (3 > 4) >
// OK
class Y { /* ... */ };
— end example ]
18
A template-parameter of a template template-parameter is permitted to have a default template-argument.
When such default arguments are specified, they apply to the template template-parameter in the scope of
the template template-parameter. [ Example:
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
inline void f();
inline void g();
};
template <template <class TT> class T> void A<T>::f() {
T<> t;
// error: TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
T<> t;
// OK, T<char>
}
— end example ]
19
If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-
declaration that declares a parameter pack (11.3.5), then the template-parameter is a template parameter
pack (17.6.3). A template parameter pack that is a parameter-declaration whose type contains one or
more unexpanded parameter packs is a pack expansion. Similarly, a template parameter pack that is a
type-parameter with a template-parameter-list containing one or more unexpanded parameter packs is a pack
expansion. A template parameter pack that is a pack expansion shall not expand a parameter pack declared
in the same template-parameter-list. [ Example:
template <class... Types>
// Types is a template type parameter pack
class Tuple;
// but not a pack expansion
template <class T, int... Dims>
// Dims is a non-type template parameter pack
struct multi_array;
// but not a pack expansion
§ 17.1
311
template <class... T>
struct value_holder {
template <T... Values> struct apply { };
// Values is a non-type template parameter pack
};
// and a pack expansion
template <class... T, T... Values>
// error: Values expands template type parameter
struct static_array;
// pack T within the same template parameter list
— end example ]
17.2
Names of template specializations
[temp.names]
1
A template specialization (17.8) can be referred to by a template-id:
simple-template-id:
template-name < template-argument-listopt >
template-id:
simple-template-id
operator-function-id < template-argument-listopt >
literal-operator-id < template-argument-listopt >
template-name:
identifier
template-argument-list:
template-argument ...opt
template-argument-list , template-argument ...opt
template-argument:
constant-expression
type-id
id-expression
[ Note: The name lookup rules (6.4) are used to associate the use of a name with a template declaration; that
is, to identify a name as a template-name.
— end note ]
2
For a template-name to be explicitly qualified by the template arguments, the name must be considered to
refer to a template. [Note: Whether a name actually refers to a template cannot be known in some cases
until after argument dependent lookup is done (6.4.2).
— end note ] A name is considered to refer to a
template if name lookup finds a template-name or an overload set that contains a function template. A name
is also considered to refer to a template if it is an unqualified-id followed by a < and name lookup finds either
one or more functions or finds nothing.
3
When a name is considered to be a template-name, and it is followed by a <, the < is always taken as the
delimiter of a template-argument-list and never as the less-than operator. When parsing a template-argument-
list, the first non-nested >137 is taken as the ending delimiter rather than a greater-than operator. Similarly,
the first non-nested >> is treated as two consecutive but distinct > tokens, the first of which is taken as
the end of the template-argument-list and completes the template-id. [Note: The second > token produced
by this replacement rule may terminate an enclosing template-id construct or it may be part of a different
construct (e.g., a cast). — end note ]
[ Example:
template<int i> class X { /* ... */ };
X< 1>2 > x1;
// syntax error
X<(1>2)> x2;
// OK
template<class T> class Y { /* ... */ };
Y<X<1>> x3;
// OK, same as Y<X<1> > x3;
Y<X<6>>1>> x4;
// syntax error
Y<X<(6>>1)>> x5;
// OK
— end example ]
4
The keyword template is said to appear at the top level in a qualified-id if it appears outside of a template-
argument-list or decltype-specifier. In a qualified-id of a declarator-id or in a qualified-id formed by a
class-head-name (Clause 12) or enum-head-name (10.2), the keyword template shall not appear at the top
137) A > that encloses the type-id of a dynamic_cast, static_cast, reinterpret_cast or const_cast, or which encloses the
template-arguments of a subsequent template-id, is considered nested for the purpose of this description.
§ 17.2
312
level. In a qualified-id used as the name in a typename-specifier (17.7), elaborated-type-specifier (10.1.7.3),
using-declaration (10.3.3), or class-or-decltype (Clause 13), an optional keyword template appearing at the
top level is ignored. In these contexts, a < token is always assumed to introduce a template-argument-list. In
all other contexts, when naming a template specialization of a member of an unknown specialization (17.7.2.1),
the member template name shall be prefixed by the keyword template. [ Example:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>();
// ill-formed: < means less than
T* p2 = p->template alloc<200>();
// OK: < starts template argument list
T::adjust<100>();
// ill-formed: < means less than
T::template adjust<100>();
// OK: < starts template argument list
}
— end example ]
5
A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template
or an alias template. [ Note: The keyword template may not be applied to non-template members of class
templates.
— end note ] [ Note: As is the case with the typename prefix, the template prefix is allowed in
cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of
the -> or . is not dependent on a template-parameter, or the use does not appear in the scope of a template.
— end note ] [ Example:
template <class T> struct A {
void f(int);
template <class U> void f(U);
};
template <class T> void f(T t) {
A<T> a;
a.template f<>(t);
// OK: calls template
a.template f(t);
// error: not a template-id
}
template <class T> struct B {
template <class T2> struct C { };
};
// OK: T::template C names a class template:
template <class T, template <class X> class TT = T::template C> struct D { };
D<B<int> > db;
— end example ]
6
A simple-template-id that names a class template specialization is a class-name (Clause 12).
7
A template-id that names an alias template specialization is a type-name.
8
When the template-name of a simple-template-id names a constrained non-function template or a constrained
template template-parameter, but not a member template that is a member of an unknown specialization
(17.7), and all template-arguments in the simple-template-id are non-dependent (17.7.2.4), the associated
constraints (17.4.2) of the constrained template shall be satisfied (17.4.1). [ Example:
template<typename T> concept C1 = sizeof(T) != sizeof(int);
template<C1 T> struct S1 { };
template<C1 T> using Ptr = T*;
S1<int>* p;
// error: constraints not satisfied
Ptr<int> p;
// error: constraints not satisfied
template<typename T>
struct S2 { Ptr<int> x; };
// error, no diagnostic required
§ 17.2
313
template<typename T>
struct S3 { Ptr<T> x; };
// OK, satisfaction is not required
S3<int> x;
// error: constraints not satisfied
template<template<C1 T> class X>
struct S4 {
X<int> x;
// error, no diagnostic required
};
template<typename T> concept C2 = sizeof(T) == 1;
template<C2 T> struct S { };
template struct S<char[2]>;
// error: constraints not satisfied
template<> struct S<char[2]> { };
// error: constraints not satisfied
— end example ]
17.3
Template arguments
[temp.arg]
1
There are three forms of template-argument, corresponding to the three forms of template-parameter : type,
non-type and template. The type and form of each template-argument specified in a template-id shall
match the type and form specified for the corresponding parameter declared by the template in its template-
parameter-list. When the parameter declared by the template is a template parameter pack (17.6.3), it will
correspond to zero or more template-arguments. [ Example:
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
Array<int> v1(20);
typedef std::complex<double> dcomplex;
// std::complex is a standard library template
Array<dcomplex> v2(30);
Array<dcomplex> v3(40);
void bar() {
v1[3] = 7;
v2[3] = v3.elem(4) = dcomplex(7,8);
}
— end example ]
2
In a template-argument, an ambiguity between a type-id and an expression is resolved to a type-id, regardless
of the form of the corresponding template-parameter.138 [ Example:
template<class T> void f();
template<int I> void f();
void g() {
f<int()>();
// int() is a type-id: call the first f()
}
— end example ]
3
The name of a template-argument shall be accessible at the point where it is used as a template-argument.
[ Note: If the name of the template-argument is accessible at the point where it is used as a template-argument,
there is no further access restriction in the resulting instantiation where the corresponding template-parameter
name is used.
— end note ] [ Example:
138) There is no such ambiguity in a default template-argument because the form of the template-parameter determines the
allowable forms of the template-argument.
§ 17.3
314
template<class T> class X {
static T t;
};
class Y {
private:
struct S { /* ... */ };
X<S> x;
// OK: S is accessible
// X<Y::S> has a static member of type Y::S
// OK: even though Y::S is private
};
X<Y::S> y;
// error: S not accessible
— end example ] For a template-argument that is a class type or a class template, the template definition has
no special access rights to the members of the template-argument. [ Example:
template <template <class TT> class T> class A {
typename T<int>::S s;
};
template <class U> class B {
private:
struct S { /* ... */ };
};
A<B> b;
// ill-formed: A has no access to B::S
— end example ]
4
When template argument packs or default template-arguments are used, a template-argument list can be
empty. In that case the empty <> brackets shall still be used as the template-argument-list. [ Example:
template<class T = char> class String;
String<>* p;
// OK: String<char>
String* q;
// syntax error
template<class ... Elements> class Tuple;
Tuple<>* t;
// OK: Elements is empty
Tuple* u;
// syntax error
— end example ]
5
An explicit destructor call (15.4) for an object that has a type that is a class template specialization may
explicitly specify the template-arguments. [ Example:
template<class T> struct A {
~A();
};
void f(A<int>* p, A<int>* q) {
p->A<int>::~A();
// OK: destructor call
q->A<int>::~A<int>();
// OK: destructor call
}
— end example ]
6
If the use of a template-argument gives rise to an ill-formed construct in the instantiation of a template
specialization, the program is ill-formed.
7
When name lookup for the name in a template-id finds an overload set, both non-template functions in the
overload set and function templates in the overload set for which the template-arguments do not match the
template-parameter s are ignored. If none of the function templates have matching template-parameter s, the
program is ill-formed.
8
When a simple-template-id does not name a function, a default template-argument is implicitly instantiated
(17.8.1) when the value of that default argument is needed. [ Example:
template<typename T, typename U = int> struct S { };
S<bool>* p;
// the type of p is S<bool, int>*
The default argument for U is instantiated to form the type S<bool, int>*.
— end example ]
§ 17.3
315
9
A template-argument followed by an ellipsis is a pack expansion (17.6.3).
17.3.1
Template type arguments
[temp.arg.type]
1
A template-argument for a template-parameter which is a type shall be a type-id.
2
[ Example:
template <class T> class X { };
template <class T> void f(T t) { }
struct { } unnamed_obj;
void f() {
struct A { };
enum { e1 };
typedef struct { } B;
B b;
X<A> x1;
// OK
X<A*> x2;
// OK
X<B> x3;
// OK
f(e1);
// OK
f(unnamed_obj);
// OK
f(b);
// OK
}
— end example ] [ Note: A template type argument may be an incomplete type (6.7). — end note ]
17.3.2
Template non-type arguments
[temp.arg.nontype]
1
If the type of a template-parameter contains a placeholder type (10.1.7.4, 17.1), the deduced parameter type is
determined from the type of the template-argument by placeholder type deduction (10.1.7.4.1). If a deduced
parameter type is not permitted for a template-parameter declaration (17.1), the program is ill-formed.
2
A template-argument for a non-type template-parameter shall be a converted constant expression (8.6) of the
type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of
the constant expression shall not refer to (or for a pointer type, shall not be the address of):
(2.1)
a subobject (6.6.2),
(2.2)
a temporary object (15.2),
(2.3)
a string literal (5.13.5),
(2.4)
the result of a typeid expression (8.5.1.8), or
(2.5)
a predefined __func__ variable (11.4.1).
[ Note: If the template-argument represents a set of overloaded functions (or a pointer or member pointer to
such), the matching function is selected from the set (16.4).
— end note ]
3
[ Example:
template<const int* pci> struct X { /* ... */ };
int ai[10];
X<ai> xi;
// array to pointer and qualification conversions
struct Y { /* ... */ };
template<const Y& b> struct Z { /* ... */ };
Y y;
Z<y> z;
// no conversion, but note extra cv-qualification
template<int (&pa)[5]> struct W { /* ... */ };
int b[5];
W<b> w;
// no conversion
void f(char);
void f(int);
template<void (*pf)(int)> struct A { /* ... */ };
A<&f> a;
// selects f(int)
§ 17.3.2
316
template<auto n> struct B { /* ... */ };
B<5> b1;
// OK: template parameter type is int
B<’a’> b2;
// OK: template parameter type is char
B<2.5> b3;
// error: template parameter type cannot be double
— end example ]
4
[ Note: A string literal (5.13.5) is not an acceptable template-argument. [ Example:
template<class T, const char* p> class X {
/* ... */
};
X<int, "Studebaker"> x1;
// error: string literal as template-argument
const char p[] = "Vivisectionist";
X<int,p> x2;
// OK
— end example ]
— end note ]
5
[ Note: The address of an array element or non-static data member is not an acceptable template-argument.
[ Example:
template<int* p> class X { };
int a[10];
struct S { int m; static int s; } s;
X<&a[2]> x3;
// error: address of array element
X<&s.m> x4;
// error: address of non-static member
X<&s.s> x5;
// OK: address of static member
X<&S::s> x6;
// OK: address of static member
— end example ]
— end note ]
6
[ Note: A temporary object is not an acceptable template-argument when the corresponding template-parameter
has reference type. [ Example:
template<const int& CRI> struct B { /* ... */ };
B<1> b2;
// error: temporary would be required for template argument
int c = 1;
B<c> b1;
// OK
— end example ]
— end note ]
17.3.3
Template template arguments
[temp.arg.template]
1
A template-argument for a template template-parameter shall be the name of a class template or an alias
template, expressed as id-expression. When the template-argument names a class template, only primary class
templates are considered when matching the template template argument with the corresponding parameter;
partial specializations are not considered even if their parameter lists match that of the template template
parameter.
2
Any partial specializations (17.6.5) associated with the primary class template or primary variable template are
considered when a specialization based on the template template-parameter is instantiated. If a specialization
is not visible at the point of instantiation, and it would have been selected had it been visible, the program is
ill-formed, no diagnostic required. [ Example:
template<class T> class A {
// primary template
int x;
};
template<class T> class A<T*> { // partial specialization
long x;
};
template<template<class U> class V> class C {
V<int> y;
V<int*> z;
};
§ 17.3.3
317
C<A> c;
// V<int> within C<A> uses the primary template, so c.y.x has type int
// V<int*> within C<A> uses the partial specialization, so c.z.x has type long
— end example ]
3
A template-argument matches a template template-parameter P when P is at least as specialized as the
template-argument A. If P contains a parameter pack, then A also matches P if each of A’s template parameters
matches the corresponding template parameter in the template-head of P. Two template parameters match
if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are
equivalent (17.6.6.1), and for template template-parameter s, each of their corresponding template-parameter s
matches, recursively. When P’s template-head contains a template parameter pack (17.6.3), the template
parameter pack will match zero or more template parameters or template parameter packs in the template-head
of A with the same type and form as the template parameter pack in P (ignoring whether those template
parameters are template parameter packs).
[ Example:
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template<class ... Types> class C { /* ... */ };
template<auto n> class D { /* ... */ };
template<template<class> class P> class X { /* ... */ };
template<template<class ...> class Q> class Y { /* ... */ };
template<template<int> class R> class Z { /* ... */ };
X<A> xa;
// OK
X<B> xb;
// OK
X<C> xc;
// OK
Y<A> ya;
// OK
Y<B> yb;
// OK
Y<C> yc;
// OK
Z<D> zd;
// OK
— end example ] [ Example:
template <class T> struct eval;
template <template <class, class...> class TT, class T1, class...
Rest>
struct eval<TT<T1, Rest...>> { };
template <class T1> struct A;
template <class T1, class T2> struct B;
template <int N> struct C;
template <class T1, int N> struct D;
template <class T1, class T2, int N = 17> struct E;
eval<A<int>> eA;
// OK: matches partial specialization of eval
eval<B<int, float>> eB;
// OK: matches partial specialization of eval
eval<C<17>> eC;
// error: C does not match TT in partial specialization
eval<D<int, 17>> eD;
// error: D does not match TT in partial specialization
eval<E<int, float>> eE;
// error: E does not match TT in partial specialization
— end example ] [ Example:
template<typename T> concept C = requires (T t) { t.f(); };
template<typename T> concept D = C<T> && requires (T t) { t.g(); };
template<template<C> class P> struct S { };
template<C> struct X { };
template<D> struct Y { };
template<typename T> struct Z { };
S<X> s1;
// OK, X and P have equivalent constraints
S<Y> s2;
// error: P is not at least as specialized as Y
S<Z> s3;
// OK, P is at least as specialized as Z
— end example ]
§ 17.3.3
318
4
A template template-parameter P is at least as specialized as a template template-argument A if, given
the following rewrite to two function templates, the function template corresponding to P is at least as
specialized as the function template corresponding to A according to the partial ordering rules for function
templates (17.6.6.2). Given an invented class template X with the template-head of A (including default
arguments and requires-clause, if any):
(4.1)
Each of the two function templates has the same template parameters and requires-clause (if any),
respectively, as P or A.
(4.2)
Each function template has a single function parameter whose type is a specialization of X with template
arguments corresponding to the template parameters from the respective function template where, for
each template parameter PP in the template-head of the function template, a corresponding template
argument AA is formed. If PP declares a parameter pack, then AA is the pack expansion PP... (17.6.3);
otherwise, AA is the id-expression PP.
If the rewrite produces an invalid type, then P is not at least as specialized as A.
17.4
Template constraints
[temp.constr]
1
[ Note: This subclause defines the meaning of constraints on template arguments. The abstract syntax and
satisfaction rules are defined in 17.4.1. Constraints are associated with declarations in 17.4.2. Declarations
are partially ordered by their associated constraints (17.4.4).
— end note ]
17.4.1
Constraints
[temp.constr.constr]
1
A constraint is a sequence of logical operations and operands that specifies requirements on template
arguments. The operands of a logical operation are constraints. There are three different kinds of constraints:
(1.1)
conjunctions (17.4.1.1),
(1.2)
disjunctions (17.4.1.1), and
(1.3)
atomic constraints (17.4.1.2)
2
In order for a constrained template to be instantiated (17.8), its associated constraints (17.4.2) shall be
satisfied as described in the following subsections. [Note: Forming the name of a specialization of a class
template, a variable template, or an alias template (17.2) requires the satisfaction of its constraints. Overload
resolution (16.3.2) requires the satisfaction of constraints on functions and function templates.
— end note ]
17.4.1.1
Logical operations
[temp.constr.op]
1
There are two binary logical operations on constraints: conjunction and disjunction. [Note: These logical
operations have no corresponding C++ syntax. For the purpose of exposition, conjunction is spelled using the
symbol and disjunction is spelled using the symbol. The operands of these operations are called the left
and right operands. In the constraint A ∧ B, A is the left operand, and B is the right operand.
— end note ]
2
A conjunction is a constraint taking two operands. To determine if a conjunction is satisfied, the satisfaction
of the first operand is checked. If that is not satisfied, the conjunction is not satisfied. Otherwise, the
conjunction is satisfied if and only if the second operand is satisfied.
3
A disjunction is a constraint taking two operands. To determine if a disjunction is satisfied, the satisfaction
of the first operand is checked. If that is satisfied, the disjunction is satisfied. Otherwise, the disjunction is
satisfied if and only if the second operand is satisfied.
4
[ Example:
template<typename T>
constexpr bool get_value() { return T::value; }
template<typename T>
requires (sizeof(T) > 1) && get_value<T>()
void f(T);
// has associated constraint sizeof(T) > 1 ∧ get_value<T>()
void f(int);
f(’a’); // OK: calls f(int)
In the satisfaction of the associated constraints (17.4.2) of f, the constraint sizeof(char) > 1 is not satisfied;
the second operand is not checked for satisfaction.
— end example ]
§ 17.4.1.1
319
17.4.1.2
Atomic constraints
[temp.constr.atomic]
1
An atomic constraint is formed from an expression E and a mapping from the template parameters that
appear within E to template arguments involving the template parameters of the constrained entity, called
the parameter mapping (17.4.2). [ Note: Atomic constraints are formed by constraint normalization (17.4.3).
E is never a logical AND expression (8.5.14) nor a logical OR expression (8.5.15).
— end note ]
2
Two atomic constraints are identical if they are formed from the same expression and the targets of the
parameter mappings are equivalent according to the rules for expressions described in 17.6.6.1.
3
To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first
substituted into its expression. If substitution results in an invalid type or expression, the constraint is
not satisfied. Otherwise, the lvalue-to-rvalue conversion (7.1) is performed if necessary, and E shall be a
constant expression of type bool. The constraint is satisfied if and only if evaluation of E results in true.
[ Example:
template<typename T> concept C =
sizeof(T) == 4 && !true;
// requires atomic constraints sizeof(T) == 4 and !true
template<typename T> struct S {
constexpr operator bool() const { return true; }
};
template<typename T> requires (S<T>{})
void f(T);
// #1
void f(int);
// #2
void g() {
f(0);
// error: expression S<int>{} does not have type bool
}
// while checking satisfaction of deduced arguments of #1;
// call is ill-formed even though #2 is a better match
— end example ]
17.4.2
Constrained declarations
[temp.constr.decl]
1
A template declaration (Clause 17) or function declaration (11.3.5) can be constrained by the use of a
requires-clause. This allows the specification of constraints for that declaration as an expression:
constraint-expression:
logical-or-expression
2
Constraints can also be associated with a declaration through the use of constrained-parameter s in a template-
parameter-list. Each of these forms introduces additional constraint-expressions that are used to constrain
the declaration.
3
A template’s associated constraints are defined as follows:
(3.1)
If there are no introduced constraint-expressions, the declaration has no associated constraints.
(3.2)
Otherwise, if there is a single introduced constraint-expression, the associated constraints are the normal
form (17.4.3) of that expression.
(3.3)
Otherwise, the associated constraints are the normal form of a logical AND expression (8.5.14) whose
operands are in the following order:
(3.3.1)
the constraint-expression introduced by each constrained-parameter (17.1) in the declaration’s
template-parameter-list, in order of appearance, and
(3.3.2)
the constraint-expression introduced by a requires-clause following a template-parameter-list (Clause
17), and
(3.3.3)
the constraint-expression introduced by a trailing requires-clause (Clause 11) of a function declara-
tion (11.3.5).
The formation of the associated constraints establishes the order in which constraints are instantiated when
checking for satisfaction (17.4.1). [ Example:
template<typename T> concept C = true;
§ 17.4.2
320
template<C T> void f1(T);
template<typename T> requires C<T> void f2(T);
template<typename T> void f3(T) requires C<T>;
The functions f1, f2, and f3 have the associated constraint C<T>.
template<typename T> concept C1 = true;
template<typename T> concept C2 = sizeof(T) > 0;
template<C1 T> void f4(T) requires C2<T>;
template<typename T> requires C1<T> && C2<T> void f5(T);
The associated constraints of f4 and f5 are C1<T> ∧ C2<T>.
template<C1 T> requires C2<T> void f6();
template<C2 T> requires C1<T> void f7();
The associated constraints of f6 are C1<T> ∧ C2<T>, and those of f7 are C2<T> ∧ C1<T>.
— end example ]
17.4.3
Constraint normalization
[temp.constr.normal]
1
The normal form of an expression E is a constraint (17.4.1) that is defined as follows:
(1.1)
The normal form of an expression ( E ) is the normal form of E.
(1.2)
The normal form of an expression E1 || E2 is the disjunction (17.4.1.1) of the normal forms of E1 and
E2.
(1.3)
The normal form of an expression E1 && E2 is the conjunction of the normal forms of E1 and E2.
(1.4)
The normal form of an id-expression of the form C<A1, A2, ..., An>, where C names a concept,
is the normal form of the constraint-expression of C, after substituting A1, A2, ..., An for C’s
respective template parameters in the parameter mappings in each atomic constraint. If any such
substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.
[ Example:
template<typename T> concept A = T::value || true;
template<typename U> concept B = A<U*>;
template<typename V> concept C = B<V&>;
Normalization of B’s constraint-expression is valid and results in T::value (with the mapping T → U*)
∨ true (with an empty mapping), despite the expression T::value being ill-formed for a pointer type
T. Normalization of C’s constraint-expression results in the program being ill-formed, because it would
form the invalid type T&* in the parameter mapping.
— end example ]
(1.5)
The normal form of any other expression E is the atomic constraint whose expression is E and whose
parameter mapping is the identity mapping.
2
The process of obtaining the normal form of a constraint-expression is called normalization. [Note: Nor-
malization of constraint-expressions is performed when determining the associated constraints (17.4.1) of a
declaration and when evaluating the value of an id-expression that names a concept specialization (8.4.4).
— end note ]
3
[ Example:
template<typename T> concept C1 = sizeof(T) == 1;
template<typename T> concept C2 = C1<T>() && 1 == 2;
template<typename T> concept C3 = requires { typename T::type; };
template<typename T> concept C4 = requires (T x) { ++x; }
template<C2 U> void f1(U);
// #1
template<C3 U> void f2(U);
// #2
template<C4 U> void f3(U);
// #3
The associated constraints of #1 are sizeof(T) == 1 (with mapping T → U) ∧ 1 == 2.
The associated constraints of #2 are requires { typename T::type; } (with mapping T → U).
The associated constraints of #3 are requires (T x) { ++x; } (with mapping T → U). — end example ]
§ 17.4.3
321

 

 

 

 

 

 

 

Content      ..     9      10      11      12     ..