C++ Compiler Engineer
Erich.Keane@intel.com
Note: All standard excerpts are from N4778: Working Draft, Standard for Programming Language C++, 2018-10-08, Richard Smith
[intro.compliance] p2.3:
If a program contains a violation of a rule for which no diagnostic is required, this
document places no requirement on implementations with respect to that program.The characters /* start a comment, which terminates with the characters */. These comments
do not nest. The characters // start a comment, which terminates immediately before the
next new-line character. If there is a form-feed or a vertical-tab character in such a
comment, only white-space characters shall appear between it and the new-line that
terminates the comment; no diagnostic is required. In addition, some identifiers are reserved for use by C++ implementations and shall not
be used otherwise; no diagnostic is required.
— Each identifier that contains a double underscore __ or begins with an underscore
followed by an uppercase letter is reserved to the implementation for any use.
— Each identifier that begins with an underscore is reserved to the implementation for
use as a name in the global namespaceEvery program shall contain exactly one definition of every non-inline function
or variable that is odr-used in that program outside of a discarded statement
(8.4.1); no diagnostic required. A name N used in a class S shall refer to the same declaration in its context and when
re-evaluated in the completed scope of S. No diagnostic is required for a violation of
this rule.The substitution of template arguments into a requires-expression may result in the formation of invalid
types or expressions in its requirements or the violation of the semantic constraints of those requirements.
In such cases, the requires-expression evaluates to false; it does not cause the program to be ill-formed.
The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that
determines the result of the requires-expression is encountered. If substitution (if any) and semantic constraint
checking succeed, the requires-expression evaluates to true. [Note: If a requires-expression contains invalid
types or expressions in its requirements, and it does not appear within the declaration of a templated entity,
then the program is ill-formed. — end note] If the substitution of template arguments into a requirement
would always result in a substitution failure, the program is ill-formed; no diagnostic required. [Example:
template<typename T> concept C =
requires {
new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required
};
— end example]The disambiguation is purely syntactic; that is, the meaning of the names occurring in such a statement,
beyond whether they are type-names or not, is not generally used in or changed by the disambiguation. Class
templates are instantiated as necessary to determine if a qualified name is a type-name. Disambiguation
precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration. If, during
parsing, a name in a template parameter is bound differently than it would be bound during a trial parse,
the program is ill-formed. No diagnostic is required. [Note: This can occur only when the name is declared
earlier in the declaration. — end note] [Example:
struct T1 {
T1 operator()(int x) { return T1(x); }
int operator=(int x) { return x; }
T1(int) { }
};
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
void f() {
// disambiguation requires this to be parsed as a declaration:
T1(a) = 3,
T2(4), // T2 will be declared as a variable of type T1, but this will not
(*(*b)(T2(c)))(int(d)); // allow the last part of the declaration to parse properly,
// since it depends on T2 being a type-name
}
— end example]5: For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument
values exist such that an invocation of the function or constructor could be an evaluated subexpression of
a core constant expression (7.7), or, for a constructor, a constant initializer for some object (6.8.3.2), the
program is ill-formed, no diagnostic required. [Example:
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
struct B {
constexpr B(int x) : i(0) { } // x is unused
int i;
};
int global;
struct D : B {
constexpr D() : B(global) { } // ill-formed, no diagnostic required
// lvalue-to-rvalue conversion on non-constant global
};
— end example]
6: If the instantiated template specialization of a constexpr function template or member function of a class
template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that
specialization is still a constexpr function or constexpr constructor, even though a call to such a function
cannot appear in a constant expression. If no specialization of the template would satisfy the requirements
for a constexpr function or constexpr constructor when considered as a non-template function or constructor,
the template is ill-formed, no diagnostic required.An inline function or variable shall be defined in every translation unit in which it is odr-used and shall
have exactly the same definition in every case (6.2). [Note: A call to the inline function or a use of the
94) The inline keyword has no effect on the linkage of a function.
§ 9.1.6 151© ISO/IEC N4778
inline variable may be encountered before its definition appears in the translation unit. — end note] If the
definition of a function or variable appears in a translation unit before its first declaration as inline, the
program is ill-formed. If a function or variable with external linkage is declared inline in one translation
unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An
inline function or variable with external linkage shall have the same address in all translation units. [Note: A
static local variable in an inline function with external linkage always refers to the same object. A type
defined within the body of an inline function with external linkage is the same type in every translation unit.
— end note]5 If two declarations declare functions with the same name and parameter-type-list (9.2.3.5) to be members of
the same namespace or declare objects with the same name to be members of the same namespace and the
declarations give the names different language linkages, the program is ill-formed; no diagnostic is required
if the declarations appear in different translation units. Except for functions with C++ linkage, a function
declaration without a linkage specification shall not precede the first linkage specification for that function.
A function can be declared without a linkage specification after an explicit linkage specification has been
seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.
6 At most one function with a particular name can have C language linkage. Two declarations for a function
with C language linkage with the same function name (ignoring the namespace names that qualify it) that
appear in different namespace scopes refer to the same function. Two declarations for a variable with C
language linkage with the same name (ignoring the namespace names that qualify it) that appear in different
namespace scopes refer to the same variable. An entity with C language linkage shall not be declared with
the same name as a variable in global scope, unless both declarations denote the same entity; no diagnostic is
required if the declarations appear in different translation units. A variable with C language linkage shall not
be declared with the same name as a function with C language linkage (ignoring the namespace names that
qualify the respective names); no diagnostic is required if the declarations appear in different translation
units. [Note: Only one definition for an entity with a given name with C language linkage may appear in
the program (see 6.2); this implies that such an entity must not be defined in more than one namespace
scope. — end note] [Example:
int x;
namespace A {
extern "C" int f();
extern "C" int g() { return 1; }
extern "C" int h();
extern "C" int x(); // ill-formed: same name as global-space object x
}
namespace B {
extern "C" int f(); // A::f and B::f refer to the same function
extern "C" int g() { return 1; } // ill-formed, the function g with C language linkage has two definitions
}
int A::f() { return 98; } // definition for the function f with C language linkage
extern "C" int h() { return 97; } // definition for the function h with C language linkage
// A::h and ::h refer to the same function
— end example]If the defining declaration of an entity has an alignment-specifier, any non-defining declaration of that entity
shall either specify equivalent alignment or have no alignment-specifier. Conversely, if any declaration of
an entity has an alignment-specifier, every defining declaration of that entity shall specify an equivalent
alignment. No diagnostic is required if declarations of an entity have different alignment-specifiers in different
translation units. [Example:
// Translation unit #1:
struct S { int x; } s, *p = &s;
// Translation unit #2:
struct alignas(16) S; // error: definition of S lacks alignment, no diagnostic required
extern S* p;
— end example]The first declaration of a function shall specify the carries_dependency attribute for its declarator-id if any
declaration of the function specifies the carries_dependency attribute. Furthermore, the first declaration of
a function shall specify the carries_dependency attribute for a parameter if any declaration of that function
specifies the carries_dependency attribute for that parameter. If a function or one of its parameters is
declared with the carries_dependency attribute in its first declaration in one translation unit and the
same function or one of its parameters is declared without the carries_dependency attribute in its first
declaration in another translation unit, the program is ill-formed, no diagnostic required.A contract condition is a precondition or a postcondition. The first declaration of a function shall specify
all contract conditions (if any) of the function. Subsequent declarations shall either specify no contract
conditions or the same list of contract conditions; no diagnostic is required if corresponding conditions
will always evaluate to the same value. The list of contract conditions of a function shall be the same if
the declarations of that function appear in different translation units; no diagnostic required. If a friend
declaration is the first declaration of the function in a translation unit and has a contract condition, the
declaration shall be a definition and shall be the only declaration of the function in the translation unit.The attribute-token noreturn specifies that a function does not return. It shall appear at most once in
each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to
the declarator-id in a function declaration. The first declaration of a function shall specify the noreturn
attribute if any declaration of that function specifies the noreturn attribute. If a function is declared with
the noreturn attribute in one translation unit and the same function is declared without the noreturn
attribute in another translation unit, the program is ill-formed, no diagnostic required[Note: There shall be exactly one definition of a static data member that is odr-used (6.2) in a program; no
diagnostic is required. — end note] Unnamed classes and classes contained directly or indirectly within
unnamed classes shall not contain static data members.A virtual function declared in a class shall be defined, or declared pure (10.6.3) in that class, or both; no
diagnostic is required (6.2).
If an overriding function specifies contract conditions (9.11.4), it shall specify the same list of contract
conditions as its overridden functions; no diagnostic is required if corresponding conditions will always
evaluate to the same value. Otherwise, it is considered to have the list of contract conditions from one of
its overridden functions; the names in the contract conditions are bound, and the semantic constraints are
checked, at the point where the contract conditions appear. Given a virtual function f with a contract
condition that odr-uses *this (6.2), the class of which f is a direct member shall be be an unambiguous and
accessible base class of any class in which f is overridden. If a function overrides more than one function, all
of the overridden functions shall have the same list of contract conditions (9.11.4); no diagnostic is required if
corresponding conditions will always evaluate to the same value. [Example:
struct A {
virtual void g() [[expects: x == 0]];
int x = 42;
};
int x = 42;
struct B {
virtual void g() [[expects: x == 0]];
}
struct C : A, B {
virtual void g(); // error: preconditions of overridden functions are not the same
};
— end example
A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype
that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class, it shall
be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the
mem-initializer is the target constructor. The target constructor is selected by overload resolution. Once the
target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to
itself directly or indirectly, the program is ill-formed, no diagnostic required. [Example:
struct C {
C( int ) { } // #1: non-delegating constructor
C(): C(42) { } // #2: delegates to #1
C( char c ) : C(42.0) { } // #3: ill-formed due to recursion with #4
C( double d ) : C(’a’) { } // #4: ill-formed due to recursion with #3
};
— end example]
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 15.5.4.3.5. A declaration whose literal-operator-id uses such a literal
suffix identifier is ill-formed, no diagnostic required.
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 (12.8.1) unless
the corresponding specialization is explicitly instantiated (12.8.2) in some translation unit; no diagnostic is
required.
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
(12.7), and all template-arguments in the simple-template-id are non-dependent (12.7.2.4), the associated
constraints (12.4.2) of the constrained template shall be satisfied (12.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
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]
Any partial specializations (12.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;
};
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]
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 7→ 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]
When a member function, a member class, a member enumeration, a static data member or a member
template of a class template is defined outside of the class template definition, the member definition is defined
as a template definition in which the template-head is equivalent to that of the class template (12.6.6.1).
The names of the template parameters used in the definition of the member may be different from the
template parameter names used in the class template definition. The template argument list following the
class template name in the member definition shall name the parameters in the same order as the one used
in the template parameter list of the member. Each template parameter pack shall be expanded with an
ellipsis in the template argument list. [Example:
template<class T1, class T2> struct A {
void f1();
void f2();
};
template<class T2, class T1> void A<T2,T1>::f1() { } // OK
template<class T2, class T1> void A<T1,T2>::f2() { } // error
template<class ... Types> struct B {
void f3();
void f4();
};
template<class ... Types> void B<Types ...>::f3() { } // OK
template<class ... Types> void B<Types>::f4() { } // error
template<typename T> concept C = true;
template<typename T> concept D = true;
§ 12.6.1 331© ISO/IEC N4778
template<C T> struct S {
void f();
void g();
void h();
template<D U> struct Inner;
};
template<C A> void S<A>::f() { } // OK: template-heads match
template<typename T> void S<T>::g() { } // error: no matching declaration for S<T>
template<typename T> requires C<T> // error (no diagnostic required): template-heads are
void S<T>::h() { } // functionally equivalent but not equivalent
template<C X> template<D Y>
struct S<X>::Inner { }; // OK
— end example]
A primary class template declaration is one in which the class template name is an identifier. A template
declaration in which the class template name is a simple-template-id is a partial specialization of the class
template named in the simple-template-id. A partial specialization of a class template provides an alternative
definition of the template that is used instead of the primary definition when the arguments in a specialization
match those given in the partial specialization (12.6.5.1). The primary template shall be declared before
§ 12.6.5 339© ISO/IEC N4778
any specializations of that template. A partial specialization shall be declared before the first use of a class
template specialization that would make use of the partial specialization as the result of an implicit or explicit
instantiation in every translation unit in which such a use occurs; no diagnostic is required.
5 Two expressions involving template parameters are considered equivalent if two function definitions containing
the expressions would satisfy the one-definition rule (6.2), except that the tokens used to name the template
parameters may differ as long as a token used to name a template parameter in one expression is replaced by
another token that names the same template parameter in the other expression. Two lambda-expressions are
never considered equivalent. [Note: The intent is to avoid lambda-expressions appearing in the signature of a
function template with external linkage. — end note] For determining whether two dependent names (12.7.2)
are equivalent, only the name itself is considered, not the result of name lookup in the context of the template.
If multiple declarations of the same function template differ in the result of this name lookup, the result for
the first declaration is used. [Example:
template <int I, int J> void f(A<I+J>); // #1
template <int K, int L> void f(A<K+L>); // same as #1
template <class T> decltype(g(T())) h();
int g(int);
template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup. . .
{ return g(T()); } // . . . although the lookup here does find g(int)
int i = h<int>(); // template argument substitution fails; g(int)
// was not in scope at the first declaration of h()
// ill-formed, no diagnostic required: the two expressions are functionally equivalent but not equivalent
template <int N> void foo(const char (*s)[([]{}, N)]);
template <int N> void foo(const char (*s)[([]{}, N)]);
// two different declarations because the non-dependent portions are not considered equivalent
template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);
template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);
— end example] Two expressions involving template parameters that are not equivalent are functionally
equivalent if, for any given set of template arguments, the evaluation of the expression results in the same
value.
7 Two function templates are equivalent if they are declared in the same scope, have the same name, have
equivalent template-heads, and have return types, parameter lists, and trailing requires-clauses (if any) that
are equivalent using the rules described above to compare expressions involving template parameters. Two
function templates are functionally equivalent if they are declared in the same scope, have the same name,
accept and are satisfied by the same set of template argument lists, and have return types and parameter lists
that are functionally equivalent using the rules described above to compare expressions involving template
parameters. If the validity or meaning of the program depends on whether two constructs are equivalent,
and they are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required
8 [Note: This rule guarantees that equivalent declarations will be linked with one another, while not requiring
implementations to use heroic efforts to guarantee that functionally equivalent declarations will be treated as
distinct. For example, the last two declarations are functionally equivalent and would cause a program to be
ill-formed:
// guaranteed to be the same
template <int I> void f(A<I>, A<I+10>);
§ 12.6.6.1 345© ISO/IEC N4778
template <int I> void f(A<I>, A<I+10>);
// guaranteed to be different
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+11>);
// ill-formed, no diagnostic required
template <int I> void f(A<I>, A<I+10>);
template <int I> void f(A<I>, A<I+1+2+3+4>);
— end note]
5 A qualified-id is assumed to name a type if
(5.1) — it is a qualified name in a type-id-only context (see below), or
(5.2) — it is a decl-specifier of the decl-specifier-seq of a
(5.2.1) — simple-declaration or a function-definition in namespace scope,
(5.2.2) — member-declaration,
(5.2.3) — parameter-declaration in a member-declaration140, unless that parameter-declaration appears in a
default argument,
(5.2.4) — parameter-declaration in a declarator of a function or function template declaration whose
declarator-id is qualified, unless that parameter-declaration appears in a default argument,
(5.2.5) — parameter-declaration in a lambda-declarator, unless that parameter-declaration appears in a
default argument, or
(5.2.6) — parameter-declaration of a (non-type) template-parameter.
A qualified name is said to be in a type-id-only context if it appears in a type-id, new-type-id, or defining-type-id
and the smallest enclosing type-id, new-type-id, or defining-type-id is a new-type-id, defining-type-id, trailingreturn-type, default argument of a type-parameter of a template, or type-id of a static_cast, const_cast,
reinterpret_cast, or dynamic_cast. [Example:
template<class T> T::R f(); // OK, return type of a function declaration at global scope
template<class T> void f(T::R); // ill-formed (no diagnostic required), attempt to declare
// a void variable template
template<class T> struct S {
using Ptr = PtrTraits<T>::Ptr; // OK, in a defining-type-id
T::R f(T::P p) { // OK, class scope
return static_cast<T::R>(p); // OK, type-id of a static_cast
}
auto g() -> S<T*>::Ptr; // OK, trailing-return-type
};
template<typename T> void f() {
void (*pf)(T::X); // variable pf of type void* initialized with T::X
void g(T::X); // error: T::X at block scope does not denote a type
// (attempt to declare a void variable)
}
— end example]
8 The validity of a template may be checked prior to any instantiation. [Note: Knowing which names are type
names allows the syntax of every template to be checked in this way. — end note] The program is ill-formed,
no diagnostic required, if:
(8.1) — no valid specialization can be generated for a template or a substatement of a constexpr if statement
(8.4.1) within a template and the template is not instantiated, or
(8.2) — no substitution of template arguments into a partial-concept-id or requires-clause would result in a
valid expression, or
(8.3) — every valid specialization of a variadic template requires an empty template parameter pack, or
(8.4) — a hypothetical instantiation of a template immediately following its definition would be ill-formed due
to a construct that does not depend on a template parameter, or
(8.5) — the interpretation of such a construct in the hypothetical instantiation is different from the interpretation
of the corresponding construct in any actual instantiation of the template. [Note: This can happen in
situations including the following:
(8.5.1) — a type used in a non-dependent name is incomplete at the point at which a template is defined
but is complete at the point at which an instantiation is performed, or
(8.5.2) — lookup for a name in the template definition found a using-declaration, but the lookup in the
corresponding scope in the instantiation does not find any declarations because the using-declaration
was a pack expansion and the corresponding pack is empty, or
(8.5.3) — an instantiation uses a default argument or default template argument that had not been defined
at the point at which the template was defined, or
(8.5.4) — constant expression evaluation (7.7) within the template instantiation uses
(8.5.4.1) — the value of a const object of integral or unscoped enumeration type or
(8.5.4.2) — the value of a constexpr object or
(8.5.4.3) — the value of a reference or
(8.5.4.4) — the definition of a constexpr function,
and that entity was not defined when the template was defined, or
§ 12.7 351© ISO/IEC N4778
(8.5.5) — a class template specialization or variable template specialization that is specified by a nondependent simple-template-id is used by the template, and either it is instantiated from a partial
specialization that was not defined when the template was defined or it names an explicit
specialization that was not declared when the template was defined.
— end note]
Otherwise, no diagnostic shall be issued for a template for which a valid specialization can be generated.
[Note: If a template is instantiated, errors will be diagnosed according to the other rules in this document.
Exactly when these errors are diagnosed is a quality of implementation issue. — end note] [Example:
int j;
template<class T> class X {
void f(T t, int i, char* p) {
t = i; // diagnosed if X::f is instantiated, and the assignment to t is an error
p = i; // may be diagnosed even if X::f is not instantiated
p = j; // may be diagnosed even if X::f is not instantiated
}
void g(T t) {
+; // may be diagnosed even if X::g is not instantiated
}
};
template<class... T> struct A {
void operator++(int, T... t); // error: too many parameters
};
template<class... T> union X : T... { }; // error: union with base class
template<class... T> struct A : T..., T... { }; // error: duplicate base class
— end example]
If a qualified-id in which the nested-name-specifier refers to the current instantiation is not a member of
the current instantiation or a member of an unknown specialization, the program is ill-formed even if the
template containing the qualified-id is not instantiated; no diagnostic required. Similarly, if the id-expression
in a class member access expression for which the type of the object expression is the current instantiation
does not refer to a member of the current instantiation or a member of an unknown specialization, the
program is ill-formed even if the template containing the member access expression is not instantiated; no
diagnostic required. [Example:
template<class T> class A {
typedef int type;
void f() {
A<T>::type i; // OK: refers to a member of the current instantiation
typename A<T>::other j; // error: neither a member of the current instantiation nor
// a member of an unknown specialization
}
};
— end example]
A specialization for a function template, a member function template, or of a member function or static
data member of a class template may have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any such specialization that has a point
of instantiation within the translation unit, the end of the translation unit is also considered a point of
instantiation. A specialization for a class template has at most one point of instantiation within a translation
unit. A specialization for any template may have points of instantiation in multiple translation units.
If two different points of instantiation give a template specialization different meanings according to the
one-definition rule (6.2), the program is ill-formed, no diagnostic required.
17 The partial-concept-ids and requires-clause of a template specialization or member function are not instantiated
along with the specialization or function itself, even for a member function of a local class; substitution
into the atomic constraints formed from them is instead performed as specified in 12.4.2 and 12.4.1.2 when
§ 12.8.1 367© ISO/IEC N4778
determining whether the constraints are satisfied. [Note: The satisfaction of constraints is determined during
name lookup or overload resolution (11.3). — end note] [Example:
template<typename T> concept C = sizeof(T) > 2;
template<typename T> concept D = C<T> && sizeof(T) > 4;
template<typename T> struct S {
S() requires C<T> { } // #1
S() requires D<T> { } // #2
};
S<char> s1; // error: no matching constructor
S<char[8]> s2; // OK, calls #2
When S<char> is instantiated, both constructors are part of the specialization. Their constraints are not
satisfied, and they suppress the implicit declaration of a default constructor for S<char> (10.3.4.1), so there
is no viable constructor for s1. — end example] [Example:
template<typename T> struct S1 {
template<typename U>
requires false
struct Inner1; // ill-formed, no diagnostic required
};
template<typename T> struct S2 {
template<typename U>
requires (sizeof(T[-(int)sizeof(T)]) > 1)
struct Inner2; // ill-formed, no diagnostic required
};
The class S1<T>::Inner1 is ill-formed, no diagnostic required, because it has no valid specializations. S2 is
ill-formed, no diagnostic required, since no substitution into the constraints of its Inner2 template would
result in a valid expression. — end example]
If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition
in the same translation unit, the definition shall follow the declaration. An entity that is the subject of
an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit
instantiation (12.8.1) in the translation unit shall be the subject of an explicit instantiation definition
somewhere in the program; otherwise the program is ill-formed, no diagnostic required. [Note: This rule does
apply to inline functions even though an explicit instantiation declaration of such an entity has no other
normative effect. This is needed to ensure that if the address of an inline function is taken in a translation
unit in which the implementation chose to suppress the out-of-line body, another translation unit will supply
the body. — end note] An explicit instantiation declaration shall not name a specialization of a template
with internal linkage.
If a template, a member template or a member of a class template is explicitly specialized then that
specialization shall be declared before the first use of that specialization that would cause an implicit
instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If
the program does not provide a definition for an explicit specialization and either the specialization is used in
a way that would cause an implicit instantiation to take place or the member is a virtual member function,
the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit
specialization that is declared but not defined. [Example:
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
template<class T> struct A {
enum E : T;
enum class S : T;
};
template<> enum A<int>::E : int { eint }; // OK
template<> enum class A<int>::S : int { sint }; // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { sT };
template<> enum A<char>::E : char { echar }; // ill-formed, A<char>::E was instantiated
// when A<char> was instantiated
template<> enum class A<char>::S : char { schar }; // OK
— end example]
7 The substitution occurs in all types and expressions that are used in the function type and in template
parameter declarations. The expressions include not only constant expressions such as those that appear in
array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions)
inside sizeof, decltype, and other contexts that allow non-constant expressions. The substitution proceeds
in lexical order and stops when a condition that causes deduction to fail is encountered. If substitution into
different declarations of the same function template would cause template instantiations to occur in a different
order or not at all, the program is ill-formed; no diagnostic required. [Note: The equivalent substitution in
exception specifications is done only when the noexcept-specifier is instantiated, at which point a program is
ill-formed if the substitution results in an invalid type or expression. — end note] [Example:
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T> auto g(typename A<T>::X) -> typename T::X;
template <class T> void g(...) { }
template <class T> typename T::X h(typename A<T>::X);
template <class T> auto h(typename A<T>::X) -> typename T::X; // redeclaration
§ 12.9.2 378© ISO/IEC N4778
template <class T> void h(...) { }
void x() {
f<int>(0); // OK, substituting return type causes deduction to fail
g<int>(0); // error, substituting parameter type instantiates A<int>
h<int>(0); // ill-formed, no diagnostic required
}
— end example]
8 If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression
is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [Note:
If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution
process. — end note] Only invalid types and expressions in the immediate context of the function type, its
template parameter types, and its explicit-specifier can result in a deduction failure. [Note: The substitution
into types and expressions can result in effects such as the instantiation of class template specializations
and/or function template specializations, the generation of implicitly-defined functions, etc. Such effects are
not in the “immediate context” and can result in the program being ill-formed. — end note]
3 A translation unit shall include a header only outside of any declaration or definition, and shall include the
header lexically before the first reference in that translation unit to any of the entities declared in that header.
No diagnostic is required.
The program’s definitions are used instead of the default versions supplied by the implementation (16.6).
Such replacement occurs prior to program startup (6.2, 6.8.3). The program’s declarations shall not be
specified as inline. No diagnostic is required.
If the semantic requirements of a declaration’s constraints (15.4.1.3) are not satisfied at the point of use, the
program is ill-formed, no diagnostic required
The contents of the header <cstdarg> are the same as the C standard library header <stdarg.h>, with the
following changes: The restrictions that ISO C places on the second parameter to the va_start macro in
header <stdarg.h> are different in this document. The parameter parmN is the rightmost parameter in the
variable parameter list of the function definition (the one just before the ...).221 If the parameter parmN is a
pack expansion (12.6.3) or an entity resulting from a lambda capture (7.5.5), the program is ill-formed, no
diagnostic required. If the parameter parmN is of a reference type, or of a type that is not compatible with
the type that results when passing an argument for which there is no parameter, the behavior is undefined.
5 Note B: Notwithstanding the provisions of 19.15.2, and pursuant to 15.5.4.2.1, a program may specialize
common_type<T1, T2> for types T1 and T2 such that is_same_v<T1, decay_t<T1>> and is_same_v<T2,
decay_t<T2>> are each true. [Note: Such specializations are needed when only explicit conversions are
desired between the template arguments. — end note] Such a specialization need not have a member named
type, but if it does, that member shall be a typedef-name for an accessible and unambiguous cv-unqualified
non-reference type C to which each of the types T1 and T2 is explicitly convertible. Moreover, common_type_-
t<T1, T2> shall denote the same type, if any, as does common_type_t<T2, T1>. No diagnostic is required
for a violation of this Note’s rules.
7 Note D: Notwithstanding the provisions of 19.15.2, and pursuant to 15.5.4.2.1, a program may partially specialize basic_common_reference<T, U, TQual, UQual> for types T and U such that is_same_v<T, decay_-
t<T>> and is_same_v<U, decay_t<U>> are each true. [Note: Such specializations can be used to influence
the result of common_reference, and are needed when only explicit conversions are desired between the
template arguments. — end note] Such a specialization need not have a member named type, but if it does,
that member shall be a typedef-name for an accessible and unambiguous type C to which each of the types
TQual<T> and UQual<U> is convertible. Moreover, basic_common_reference<T, U, TQual, UQual>::type
shall denote the same type, if any, as does basic_common_reference<U, T, UQual, TQual>::type. No
diagnostic is required for a violation of these rules