declaration-seq: declaration declaration-seq declaration
declaration: block-declaration nodeclspec-function-declaration function-definition template-declaration deduction-guide explicit-instantiation explicit-specialization linkage-specification namespace-definition empty-declaration attribute-declaration
block-declaration: simple-declaration asm-definition namespace-alias-definition using-declaration using-directive static_assert-declaration alias-declaration opaque-enum-declaration
nodeclspec-function-declaration: attribute-specifier-seq declarator ;
alias-declaration: using identifier attribute-specifier-seq = defining-type-id ;
simple-declaration: decl-specifier-seq init-declarator-list ; attribute-specifier-seq decl-specifier-seq init-declarator-list ; attribute-specifier-seq decl-specifier-seq ref-qualifier [ identifier-list ] initializer ;
static_assert-declaration: static_assert ( constant-expression ) ; static_assert ( constant-expression , string-literal ) ;
empty-declaration: ;
attribute-declaration: attribute-specifier-seq ;
attribute-specifier-seq decl-specifier-seq init-declarator-list ;is divided into three parts.
static_assert(char(-1) < 0, "this library requires plain 'char' to be signed");
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-seqThe optional attribute-specifier-seq in a decl-specifier-seq appertains to the type determined by the preceding decl-specifiers ([dcl.meaning]).
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 mutableAt most one storage-class-specifier shall appear in a given decl-specifier-seq, except that thread_local may appear with static or extern.
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
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 }
class X { mutable const int* p; // OK mutable int* const q; // ill-formed };
function-specifier: virtual explicit
using handler_t = void (*)(int); extern handler_t ignore; extern void (*ignore)(int); // redeclare ignore using cell = pair<void*, cell*>; // ill-formed
typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I;
struct S { typedef struct A { } A; // OK typedef struct B B; // OK typedef A A; // error };
struct S; typedef struct S S; int main() { struct S* p; // OK } struct S { }; // OK
struct S { S(); ~S(); }; typedef struct S T; S a = T(); // OK struct T * p; // error
constexpr 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
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; }
struct Length { constexpr explicit Length(int i = 0) : val(i) { } private: int val; };
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 };
constexpr 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; }
struct pixel { int x, y; }; constexpr pixel ur = { 1294, 1024 }; // OK constexpr pixel origin; // error: initializer missing
type-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-seqThe optional attribute-specifier-seq in a type-specifier-seq or a defining-type-specifier-seq appertains to the type denoted by the preceding type-specifiers or defining-type-specifiers ([dcl.meaning]).
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&
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. }
elaborated-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 ;In the first case, the attribute-specifier-seq, if any, appertains to the class being declared; the attributes in the attribute-specifier-seq are thereafter considered attributes of the class whenever it is named.
( 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
auto x = 5, *y = &x; // OK: auto is int auto a = 5, b = { 1, 2 }; // error: different types for auto
auto f() { } // OK, return type is void auto* g() { } // error, cannot deduce auto* from void()
auto 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 }
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
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>
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
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
const 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)
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
enum-name: identifier
enum-specifier: enum-head { enumerator-list } enum-head { enumerator-list , }
enum-head: enum-key attribute-specifier-seq enum-head-name enum-base
enum-head-name: nested-name-specifier identifier
opaque-enum-declaration: enum-key attribute-specifier-seq nested-name-specifier identifier enum-base ;
enum-key: enum enum class enum struct
enum-base: : type-specifier-seq
enumerator-list: enumerator-definition enumerator-list , enumerator-definition
enumerator-definition: enumerator enumerator = constant-expression
enumerator: identifier attribute-specifier-seqThe optional attribute-specifier-seq in the enum-head and the opaque-enum-declaration appertains to the enumeration; the attributes in that attribute-specifier-seq are thereafter considered attributes of the enumeration whenever it is named.
enum color { red, yellow, green=20, blue };
color col = red;
color* cp = &col;
if (*cp == blue) // ...
makes color a type describing various colors, and then declares
col as an object of that type, and cp as a pointer to an
object of that type.color c = 1; // error: type mismatch, no conversion from int to color int i = yellow; // OK: yellow converted to integral value 1, integral promotion
enum class Col { red, yellow, green }; int x = Col::red; // error: no Col to int conversion Col y = Col::red; if (y) { } // error: no Col to bool conversion
enum direction { left='l', right='r' }; void g() { direction d; // OK d = left; // OK d = direction::right; // OK } enum class altitude { high='h', low='l' }; void h() { altitude a; // OK a = high; // error: high not in scope a = altitude::low; // OK }
struct X { enum direction { left='l', right='r' }; int f(int i) { return i==left ? 0 : i==right ? 1 : 2; } }; void g(X* p) { direction d; // error: direction not in scope int i; i = p->f(left); // error: left not in scope i = p->f(X::right); // OK i = p->f(p->left); // OK // ... }
namespace-name: identifier namespace-alias
namespace-definition: named-namespace-definition unnamed-namespace-definition nested-namespace-definition
named-namespace-definition: inline namespace attribute-specifier-seq identifier { namespace-body }
unnamed-namespace-definition: inline namespace attribute-specifier-seq { namespace-body }
nested-namespace-definition: namespace enclosing-namespace-specifier :: identifier { namespace-body }
enclosing-namespace-specifier: identifier enclosing-namespace-specifier :: identifier
namespace-body: declaration-seq
namespace Outer { int i; namespace Inner { void f() { i++; } // Outer::i int i; void g() { i++; } // Inner::i } }
namespace Q { namespace V { void f(); // enclosing namespaces are the global namespace, Q, and Q::V class C { void m(); }; } void V::f() { // enclosing namespaces are the global namespace, Q, and Q::V extern void h(); // ... so this declares Q::V::h } void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q::V } }
namespace E { namespace I { B } }
namespace A::B::C { int i; }
namespace A { namespace B { namespace C { int i; } } }
inline namespace unique { /* empty body */ } using namespace unique ; namespace unique { namespace-body }where inline appears if and only if it appears in the unnamed-namespace-definition and all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the translation unit.
namespace { int i; } // unique::i void f() { i++; } // unique::i++ namespace A { namespace { int i; // A::unique::i int j; // A::unique::j } void g() { i++; } // A::unique::i++ } using namespace A; void h() { i++; // error: unique::i or A::unique::i A::i++; // A::unique::i j++; // A::unique::j }
namespace X { void f() { /* ... */ } // OK: introduces X::f() namespace M { void g(); // OK: introduces X::M::g() } using M::g; void g(); // error: conflicts with X::M::g() }
namespace Q { namespace V { void f(); } void V::f() { /* ... */ } // OK void V::g() { /* ... */ } // error: g() is not yet a member of V namespace V { void g(); } } namespace R { void Q::V::g() { /* ... */ } // error: R doesn't enclose Q }
// Assume f and g have not yet been declared. void h(int); template <class T> void f2(T); namespace A { class X { friend void f(X); // A::f(X) is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend // ::h not considered friend void f2<>(int); // ::f2<>(int) is a friend }; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::g void f(X) { /* ... */ } // definition of A::f void h(int) { /* ... */ } // definition of A::h // A::f, A::g and A::h are visible here and known to be friends } using A::x; void h() { A::f(x); A::X::f(x); // error: f is not a member of A::X A::X::Y::g(); // error: g is not a member of A::X::Y }
namespace Company_with_very_long_name { /* ... */ } namespace CWVLN = Company_with_very_long_name; namespace CWVLN = Company_with_very_long_name; // OK: duplicate namespace CWVLN = CWVLN;
using-declaration: using using-declarator-list ;
using-declarator-list: using-declarator ... using-declarator-list , using-declarator ...
using-declarator: typename nested-name-specifier unqualified-id
struct B { void f(char); void g(char); enum E { e }; union { int x; }; }; struct D : B { using B::f; void f(int) { f('c'); } // calls B::f(char) void g(int) { g('c'); } // recursively calls D::g(int) };
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x; // OK: B::g and D::g introduced
class C { int g(); }; class D2 : public B { using B::f; // OK: B is a base of D2 using B::e; // OK: e is an enumerator of base B using B::x; // OK: x is a union member of base B using C::g; // error: C isn't a base of D2 };
struct A { template <class T> void f(T); template <class T> struct X { }; }; struct B : A { using A::f<double>; // ill-formed using A::X<int>; // ill-formed };
struct X { int i; static int s; }; void f() { using X::i; // error: X::i is a class member and this is not a member declaration. using X::s; // error: X::s is a class member and this is not a member declaration. }
void f(); namespace A { void g(); } namespace X { using ::f; // global f using A::g; // A's g } void h() { X::f(); // calls ::f X::g(); // calls A::g }
namespace A { int i; } namespace A1 { using A::i, A::i; // OK: double declaration } struct B { int i; }; struct X : B { using B::i, B::i; // error: double member declaration };
namespace A { void f(int); } using A::f; // f is a synonym for A::f; that is, for A::f(int). namespace A { void f(char); } void foo() { f('a'); // calls f(int), even though f(char) exists. } void bar() { using A::f; // f is a synonym for A::f; that is, for A::f(int) and A::f(char). f('a'); // calls f(char) }
namespace A { int x; } namespace B { int i; struct g { }; struct x { }; void f(int); void f(double); void g(char); // OK: hides struct g } void func() { int i; using B::i; // error: i declared twice void f(char); using B::f; // OK: each f is a function f(3.5); // calls B::f(double) using B::g; g('a'); // calls B::g(char) struct g g1; // g1 has class type B::g using B::x; using A::x; // OK: hides struct B::x x = 99; // assigns to A::x struct x x1; // x1 has class type B::x }
namespace B { void f(int); void f(double); } namespace C { void f(int); void f(double); void f(char); } void h() { using B::f; // B::f(int) and B::f(double) using C::f; // C::f(int), C::f(double), and C::f(char) f('h'); // calls C::f(char) f(1); // error: ambiguous: B::f(int) or C::f(int)? void f(int); // error: f(int) conflicts with C::f(int) and B::f(int) }
struct B { virtual void f(int); virtual void f(char); void g(int); void h(int); }; struct D : B { using B::f; void f(int); // OK: D::f(int) overrides B::f(int); using B::g; void g(char); // OK using B::h; void h(int); // OK: D::h(int) hides B::h(int) }; void k(D* p) { p->f(1); // calls D::f(int) p->f('a'); // calls B::f(char) p->g(1); // calls B::g(int) p->g('a'); // calls D::g(char) } struct B1 { B1(int); }; struct B2 { B2(int); }; struct D1 : B1, B2 { using B1::B1; using B2::B2; }; D1 d1(0); // ill-formed: ambiguous struct D2 : B1, B2 { using B1::B1; using B2::B2; D2(int); // OK: D2::D2(int) hides B1::B1(int) and B2::B2(int) }; D2 d2(0); // calls D2::D2(int)
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x(); // error: overload resolution selects A::x, but A is an ambiguous base class
}
class A { private: void f(char); public: void f(int); protected: void g(); }; class B : public A { using A::f; // error: A::f(char) is inaccessible public: using A::g; // B::g is a public synonym for A::g };
using-directive: attribute-specifier-seq using namespace nested-name-specifier namespace-name ;
namespace A { int i; namespace B { namespace C { int i; } using namespace A::B::C; void f1() { i = 5; // OK, C::i visible in B and hides A::i } } namespace D { using namespace B; using namespace C; void f2() { i = 5; // ambiguous, B::C::i or A::i? } } void f3() { i = 5; // uses A::i } } void f4() { i = 5; // ill-formed; neither i is visible }
namespace M {
int i;
}
namespace N {
int i;
using namespace M;
}
void f() {
using namespace N;
i = 7; // error: both M::i and N::i are visible
}
namespace A { int i; } namespace B { int i; int j; namespace C { namespace D { using namespace A; int j; int k; int a = i; // B::i hides A::i } using namespace D; int k = 89; // no problem yet int l = k; // ambiguous: C::k or D::k int m = i; // B::i hides A::i int n = j; // D::j hides B::j } }
namespace A { class X { }; extern "C" int g(); extern "C++" int h(); } namespace B { void X(int); extern "C" int g(); extern "C++" int h(int); } using namespace A; using namespace B; void f() { X(1); // error: name X found in two namespaces g(); // OK: name g refers to the same entity h(); // OK: overload resolution selects A::h }
namespace D { int d1; void f(char); } using namespace D; int d1; // OK: no conflict with D::d1 namespace E { int e; void f(int); } namespace D { // namespace extension int d2; using namespace E; void f(int); } void f() { d1++; // error: ambiguous ::d1 or D::d1? ::d1++; // OK D::d1++; // OK d2++; // OK: D::d2 e++; // OK: E::e f(1); // error: ambiguous: D::f(int) or E::f(int)? f('a'); // OK: D::f(char) }
asm-definition: attribute-specifier-seq asm ( string-literal ) ;The asm declaration is conditionally-supported; its meaning is implementation-defined.
linkage-specification: extern string-literal { declaration-seq } extern string-literal declarationThe string-literal indicates the required language linkage.
complex sqrt(complex); // C++ linkage by default extern "C" { double sqrt(double); // C linkage }
extern "C" // the name f1 and its function type have C language linkage; void f1(void(*pf)(int)); // pf is a pointer to a C function extern "C" typedef void FUNC(); FUNC f2; // the name f2 has C++ language linkage and the // function's type has C language linkage extern "C" FUNC f3; // the name of function f3 and the function's type have C language linkage void (*pf2)(FUNC*); // the name of the variable pf2 has C++ linkage and the type // of pf2 is “pointer to C++ function that takes one parameter of type // pointer to C function” extern "C" { static void f4(); // the name of the function f4 has internal linkage (not C language linkage) // and the function's type has C language linkage. } extern "C" void f5() { extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. } extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. void f6() { extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. }
extern "C" typedef void FUNC_c(); class C { void mf1(FUNC_c*); // the name of the function mf1 and the member function's type have // C++ language linkage; the parameter has type “pointer to C function” FUNC_c mf2; // the name of the function mf2 and the member function's type have // C++ language linkage static FUNC_c* q; // the name of the data member q has C++ language linkage and // the data member's type is “pointer to C function” }; extern "C" { class X { void mf(); // the name of the function mf and the member function's type have // C++ language linkage void mf2(void(*)()); // the name of the function mf2 has C++ language linkage; // the parameter has type “pointer to C function” }; }
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
extern "C" double f(); static double f(); // error extern "C" int i; // declaration extern "C" { int i; // definition } extern "C" static void g(); // error
attribute-specifier-seq: attribute-specifier-seq attribute-specifier
attribute-specifier: [ [ attribute-using-prefix attribute-list ] ] alignment-specifier
alignment-specifier: alignas ( type-id ... ) alignas ( constant-expression ... )
attribute-using-prefix: using attribute-namespace :
attribute-list: attribute attribute-list , attribute attribute ... attribute-list , attribute ...
attribute: attribute-token attribute-argument-clause
attribute-token: identifier attribute-scoped-token
attribute-scoped-token: attribute-namespace :: identifier
attribute-namespace: identifier
attribute-argument-clause: ( balanced-token-seq )
balanced-token-seq: balanced-token balanced-token-seq balanced-token
balanced-token: ( balanced-token-seq ) [ balanced-token-seq ] { balanced-token-seq } any token other than a parenthesis, a bracket, or a brace
[[using CC: opt(1), debug]] // same as [[CC::opt(1), CC::debug]] void f() {} [[using CC: opt(1)]] [[CC::debug]] // same as [[CC::opt(1)]] [[CC::debug]] void g() {} [[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute token void h() {}
int p[10]; void f() { int x = 42, y[5]; int(p[[x] { return x; }()]); // error: invalid attribute on a nested declarator-id and // not a function-style cast of an element of p. y[[] { return 2; }()] = 2; // error even though attributes are not allowed in this context. int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute. }
struct alignas(8) S {};
struct alignas(1) U {
S s;
}; // error: U specifies an alignment that is less strict than if the alignas(1) were omitted.
// 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;
alignas(T) alignas(A) T buffer[N];Specifying alignas(T) ensures that the final requested alignment will not be weaker than alignof(T), and therefore the program will not be ill-formed.
alignas(double) void f(); // error: alignment applied to function alignas(double) unsigned char c[sizeof(double)]; // array of characters, suitably aligned for a double extern unsigned char c[sizeof(double)]; // no alignas necessary alignas(float) extern unsigned char c[sizeof(double)]; // error: different alignment in declaration
/* Translation unit A. */ struct foo { int* a; int* b; }; std::atomic<struct foo *> foo_head[10]; int foo_array[10][10]; [[carries_dependency]] struct foo* f(int i) { return foo_head[i].load(memory_order_consume); } int g(int* x, int* y [[carries_dependency]]) { return kill_dependency(foo_array[*x][*y]); } /* Translation unit B. */ [[carries_dependency]] struct foo* f(int i); int g(int* x, int* y [[carries_dependency]]); int c = 3; void h(int i) { struct foo* p; p = f(i); do_something_with(g(&c, p->a)); do_something_with(g(p->a, &c)); }
( string-literal )
struct [[nodiscard]] error_info { /* ... */ }; error_info enable_missile_safety_mode(); void launch_missiles(); void test_missiles() { enable_missile_safety_mode(); // warning encouraged launch_missiles(); } error_info &foo(); void f() { foo(); } // warning not encouraged: not a nodiscard call, because neither // the (reference) return type nor the function is declared nodiscard