decl-specifier: storage-class-specifier defining-type-specifier function-specifier friend typedef constexpr inline
decl-specifier-seq: decl-specifier attribute-specifier-seq decl-specifier decl-specifier-seq
typedef char* Pc;
static Pc;                      // error: name missing
 void f(const Pc); // void f(char* const) (not const char*) void g(const int Pc); // void g(const int)
storage-class-specifier: static thread_local extern mutable
static char* f(); // f() has internal linkage char* f() // f() still has internal linkage { /* ... */ } char* g(); // g() has external linkage static char* g() // error: inconsistent linkage { /* ... */ } void h(); inline void h(); // external linkage inline void l(); void l(); // external linkage inline void m(); extern void m(); // external linkage static void n(); inline void n(); // internal linkage static int a; // a has internal linkage int a; // error: two definitions static int b; // b has internal linkage extern int b; // b still has internal linkage int c; // c has external linkage static int c; // error: inconsistent linkage extern int d; // d has external linkage static int d; // error: inconsistent linkage— end example
struct S;
extern S a;
extern S f();
extern void g(S);
void h() {
  g(a);                         // error: S is incomplete
  f();                          // error: S is incomplete
} — end example
class X {
  mutable const int* p;         // OK
  mutable int* const q;         // ill-formed
}; — end examplefunction-specifier: virtual explicit
typedef-name: identifier
using handler_t = void (*)(int); extern handler_t ignore; extern void (*ignore)(int); // redeclare ignore using cell = pair<void*, cell*>; // ill-formed— end example
typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I; — end example
struct S {
  typedef struct A { } A;       // OK
  typedef struct B B;           // OK
  typedef A A;                  // error
}; — end example
struct S;
typedef struct S S;
int main() {
  struct S* p;                  // OK
}
struct S { };                   // OK
 — end example
struct S {
  S();
  ~S();
};
typedef struct S T;
S a = T();                      // OK
struct T * p;                   // error
 — end exampleconstexpr void square(int &x); // OK: declaration constexpr int bufsz = 1024; // OK: definition constexpr struct pixel { // error: pixel is a type int x; int y; constexpr pixel(int); // OK: declaration }; constexpr pixel::pixel(int a) : x(a), y(x) // OK: definition { square(x); } constexpr pixel small(2); // error: square not defined, so small(2) // not constant ([expr.const]) so constexpr not satisfied constexpr void square(int &x) { // OK: definition x *= x; } constexpr pixel large(4); // OK: square defined int next(constexpr int x) { // error: not for parameters return x + 1; } extern constexpr int memsz; // error: not a definition— end example
constexpr int square(int x)
  { return x * x; }             // OK
constexpr long long_max()
  { return 2147483647; }        // OK
constexpr int abs(int x) {
  if (x < 0)
    x = -x;
  return x;                     // OK
}
constexpr int first(int n) {
  static int value = n;         // error: variable has static storage duration
  return value;
}
constexpr int uninit() {
  int a;                        // error: variable is uninitialized
  return a;
}
constexpr int prev(int x)
  { return --x; }               // OK
constexpr int g(int x, int n) { // OK
  int r = 1;
  while (--n > 0) r *= x;
  return r;
} — end example
struct Length {
  constexpr explicit Length(int i = 0) : val(i) { }
private:
  int val;
}; — end 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 exampleconstexpr int bar(int x, int y) // OK { return x + y + x*y; } // ... int bar(int x, int y) // error: redefinition of bar { return x * 2 + 3 * y; }— end example
struct pixel {
  int x, y;
};
constexpr pixel ur = { 1294, 1024 };    // OK
constexpr pixel origin;                 // error: initializer missing
 — end exampletype-specifier: simple-type-specifier elaborated-type-specifier typename-specifier cv-qualifier
type-specifier-seq: type-specifier attribute-specifier-seq type-specifier type-specifier-seq
defining-type-specifier: type-specifier class-specifier enum-specifier
defining-type-specifier-seq: defining-type-specifier attribute-specifier-seq defining-type-specifier defining-type-specifier-seq
const int ci = 3; // cv-qualified (initialized as required) ci = 4; // ill-formed: attempt to modify const int i = 2; // not cv-qualified const int* cip; // pointer to const int cip = &i; // OK: cv-qualified access path to unqualified *cip = 4; // ill-formed: attempt to modify through ptr to const int* ip; ip = const_cast<int*>(cip); // cast needed to convert const int* to int* *ip = 4; // defined: *ip points to i, a non-const object const int* ciq = new const int (3); // initialized as required int* iq = const_cast<int*>(ciq); // cast required *iq = 4; // undefined: modifies a const object
struct X {
  mutable int i;
  int j;
};
struct Y {
  X x;
  Y();
};
const Y y;
y.x.i++;                                // well-formed: mutable member can be modified
y.x.j++;                                // ill-formed: const-qualified member modified
Y* p = const_cast<Y*>(&y);              // cast away const-ness of y
p->x.i = 99;                            // well-formed: mutable member can be modified
p->x.j = 99;                            // undefined: modifies a const member
simple-type-specifier: nested-name-specifier type-name nested-name-specifier template simple-template-id nested-name-specifier template-name char char16_t char32_t wchar_t bool short int long signed unsigned float double void auto decltype-specifier
type-name: class-name enum-name typedef-name simple-template-id
decltype-specifier: decltype ( expression ) decltype ( auto )
Specifier(s)  | Type  | 
type-name  | the type named  | 
simple-template-id  | the type as defined in [temp.names]  | 
template-name  | placeholder for a type to be deduced  | 
char  | “char”  | 
unsigned char  | “unsigned char”  | 
signed char  | “signed char”  | 
char16_t  | “char16_t”  | 
char32_t  | “char32_t”  | 
bool  | “bool”  | 
unsigned  | “unsigned int”  | 
unsigned int  | “unsigned int”  | 
signed  | “int”  | 
signed int  | “int”  | 
int  | “int”  | 
unsigned short int  | “unsigned short int”  | 
unsigned short  | “unsigned short int”  | 
unsigned long int  | “unsigned long int”  | 
unsigned long  | “unsigned long int”  | 
unsigned long long int  | “unsigned long long int”  | 
unsigned long long  | “unsigned long long int”  | 
signed long int  | “long int”  | 
signed long  | “long int”  | 
signed long long int  | “long long int”  | 
signed long long  | “long long int”  | 
long long int  | “long long int”  | 
long long  | “long long int”  | 
long int  | “long int”  | 
long  | “long int”  | 
signed short int  | “short int”  | 
signed short  | “short int”  | 
short int  | “short int”  | 
short  | “short int”  | 
wchar_t  | “wchar_t”  | 
float  | “float”  | 
double  | “double”  | 
long double  | “long double”  | 
void  | “void”  | 
auto  | placeholder for a type to be deduced  | 
decltype(auto)  | placeholder for a type to be deduced  | 
decltype(expression)  | the type as defined below  | 
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 17;        // type is const int&&
decltype(i) x2;                 // type is int
decltype(a->x) x3;              // type is double
decltype((a->x)) x4 = x3;       // type is const double&
 — end example
template<class T> struct A { ~A() = delete; };
template<class T> auto h()
  -> A<T>;
template<class T> auto i(T)     // identity
  -> T;
template<class T> auto f(T)     // #1
  -> decltype(i(h<T>()));       // forces completion of A<T> and implicitly uses A<T>::~A()
                                // for the temporary introduced by the use of h().
                                // (A temporary is not introduced as a result of the use of i().)
template<class T> auto f(T)     // #2
  -> void;
auto g() -> void {
  f(42);                        // OK: calls #2. (#1 is not a viable candidate: type deduction
                                // fails ([temp.deduct]) because A<int>::~A() is implicitly used in its
                                // decltype-specifier)
}
template<class T> auto q(T)
  -> decltype((h<T>()));        // does not force completion of A<T>; A<T>::~A() is not implicitly
                                // used within the context of this decltype-specifier
void r() {
  q(42);                        // Error: deduction against q succeeds, so overload resolution selects
                                // the specialization “q(T) -> decltype((h<T>())) [with T=int]”.
                                // The return type is A<int>, so a temporary is introduced and its
                                // destructor is used, so the program is ill-formed.
} — end exampleelaborated-type-specifier: class-key attribute-specifier-seq nested-name-specifier identifier class-key simple-template-id class-key nested-name-specifier template simple-template-id enum nested-name-specifier identifier
class-key attribute-specifier-seq identifier ; friend class-key :: identifier ; friend class-key :: simple-template-id ; friend class-key nested-name-specifier identifier ; friend class-key nested-name-specifier template simple-template-id ;
friend class T;
( expression-list ) auto x = 5; // OK: x has type int const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int static auto y = 0.0; // OK: y has type double auto int r; // error: auto is not a storage-class-specifier auto f() -> int; // OK: f returns int auto g() { return 0.0; } // OK: g returns double auto h(); // OK: h's return type will be deduced when it is defined— end example
auto x = 5, *y = &x; // OK: auto is int auto a = 5, b = { 1, 2 }; // error: different types for auto— end example
auto  f() { }                   // OK, return type is void
auto* g() { }                   // error, cannot deduce auto* from void()
 — end exampleauto n = n; // error, n's type is unknown auto f(); void g() { &f; } // error, f's return type is unknown auto sum(int i) { if (i == 1) return i; // sum's return type is int else return sum(i-1)+i; // OK, sum's return type has been deduced }— end example
template <class T> auto f(T t) { return t; }    // return type deduced at instantiation time
typedef decltype(f(1)) fint_t;                  // instantiates f<int> to deduce return type
template<class T> auto f(T* t) { return *t; }
void g() { int (*p)(int*) = &f; }               // instantiates both fs to determine return types,
                                                // chooses second
 — end example
auto f();
auto f() { return 42; }                         // return type is int
auto f();                                       // OK
int f();                                        // error, cannot be overloaded with auto f()
decltype(auto) f();                             // error, auto and decltype(auto) don't match
template <typename T> auto g(T t) { return t; } // #1
template auto g(int);                           // OK, return type is int
template char g(char);                          // error, no matching template
template<> auto g(double);                      // OK, forward declaration with unknown return type
template <class T> T g(T t) { return t; }       // OK, not functionally equivalent to #1
template char g(char);                          // OK, now there is a matching template
template auto g(float);                         // still matches #1
void h() { return g(42); }                      // error, ambiguous
template <typename T> struct A {
  friend T frf(T);
};
auto frf(int i) { return i; }                   // not a friend of A<int>
 — end example
template <typename T> auto f(T t) { return t; }
extern template auto f(int);    // does not instantiate f<int>
int (*p)(int) = f;              // instantiates f<int> to determine its return type, but an explicit
                                // instantiation definition is still required somewhere in the program
 — end example
auto x1 = { 1, 2 };             // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 };           // error: cannot deduce element type
auto x3{ 1, 2 };                // error: not a single element
auto x4 = { 3 };                // decltype(x4) is std::initializer_list<int>
auto x5{ 3 };                   // decltype(x5) is int
 — end exampleconst auto &i = expr;
template <class U> void f(const U& u);
int i; int&& f(); auto x2a(i); // decltype(x2a) is int decltype(auto) x2d(i); // decltype(x2d) is int auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)— end example
template<class T> struct container {
    container(T t) {}
    template<class Iter> container(Iter beg, Iter end);
};
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
std::vector<double> v = { /* ... */ };
container c(7);                         // OK, deduces int for T
auto d = container(v.begin(), v.end()); // OK, deduces double for T
container e{5, 6};                      // error, int is not an iterator
 — end example