# Keywords
Keywords have fixed meaning defined by the C++ standard and cannot be used as identifiers. It is illegal to redefine keywords using the preprocessor in any translation unit that includes a standard library header. However, keywords lose their special meaning inside attributes.
# asm
The asm
keyword takes a single operand, which must be a string literal. It has an implementation-defined meaning, but is typically passed to the implementation's assembler, with the assembler's output being incorporated into the translation unit.
The asm
statement is a definition, not an expression, so it may appear either at block scope or namespace scope (including global scope). However, since inline assembly cannot be constrained by the rules of the C++ language, asm
may not appear inside a constexpr
function.
Example:
[[noreturn]] void halt_system() {
asm("hlt");
}
# explicit
class MyVector {
public:
explicit MyVector(uint64_t size);
};
MyVector v1(100); // ok
uint64_t len1 = 100;
MyVector v2{len1}; // ok, len1 is uint64_t
int len2 = 100;
MyVector v3{len2}; // ill-formed, implicit conversion from int to uint64_t
Since C++11 introduced initializer lists, in C++11 and later, explicit
can be applied to a constructor with any number of arguments, with the same meaning as in the single-argument case.
struct S {
explicit S(int x, int y);
};
S f() {
return {12, 34}; // ill-formed
return S{12, 34}; // ok
}
class C {
const int x;
public:
C(int x) : x(x) {}
explicit operator int() { return x; }
};
C c(42);
int x = c; // ill-formed
int y = static_cast<int>(c); // ok; explicit conversion
# noexcept
#include <iostream>
#include <stdexcept>
void foo() { throw std::runtime_error("oops"); }
void bar() {}
struct S {};
int main() {
std::cout << noexcept(foo()) << '\n'; // prints 0
std::cout << noexcept(bar()) << '\n'; // prints 0
std::cout << noexcept(1 + 1) << '\n'; // prints 1
std::cout << noexcept(S()) << '\n'; // prints 1
}
In this example, even though bar()
can never throw an exception, noexcept(bar())
is still false because the fact that bar()
cannot propagate an exception has not been explicitly specified.
void f1() { throw std::runtime_error("oops"); }
void f2() noexcept(false) { throw std::runtime_error("oops"); }
void f3() {}
void f4() noexcept {}
void f5() noexcept(true) {}
void f6() noexcept {
try {
f1();
} catch (const std::runtime_error&) {}
}
In this example, we have declared that f4
, f5
, and f6
cannot propagate exceptions. (Although an exception can be thrown during execution of f6
, it is caught and not allowed to propagate out of the function.) We have declared that f2
may propagate an exception. When the noexcept
specifier is omitted, it is equivalent to noexcept(false)
, so we have implicitly declared that f1
and f3
may propagate exceptions, even though exceptions cannot actually be thrown during the execution of f3
.
Whether or not a function is noexcept
is part of the function's type: that is, in the example above, f1
, f2
, and f3
have different types from f4
, f5
, and f6
. Therefore, noexcept
is also significant in function pointers, template arguments, and so on.
void g1() {}
void g2() noexcept {}
void (*p1)() noexcept = &g1; // ill-formed, since g1 is not noexcept
void (*p2)() noexcept = &g2; // ok; types match
void (*p3)() = &g1; // ok; types match
void (*p4)() = &g2; // ok; implicit conversion
# typename
template <class T>
auto decay_copy(T&& r) -> typename std::decay<T>::type;
template <typename T>
const T& min(const T& x, const T& y) {
return b < a ? b : a;
}
template <template <class T> typename U>
void f() {
U<int>::do_it();
U<double>::do_it();
}
# sizeof
A unary operator that yields the size in bytes of its operand, which may be either an expression or a type. If the operand is an expression, it is not evaluated. The size is a constant expression of type std::size_t
.
If the operand is a type, it must be parenthesized.
- It is illegal to apply
sizeof
to a function type. - It is illegal to apply
sizeof
to an incomplete type, includingvoid
. - If sizeof is applied to a reference type
T&
orT&&
, it is equivalent tosizeof(T)
. - When
sizeof
is applied to a class type, it yields the number of bytes in a complete object of that type, including any padding bytes in the middle or at the end. Therefore, asizeof
expression can never have a value of 0. See layout of object types (opens new window) for more details. - The
char
,signed char
, andunsigned char
types have a size of 1. Conversely, a byte is defined to be the amount of memory required to store achar
object. It does not necessarily mean 8 bits, as some systems havechar
objects longer than 8 bits.
If expr is an expression, sizeof(
expr)
is equivalent to sizeof(T)
where T
is the type of expr.
int a[100];
std::cout << "The number of bytes in `a` is: " << sizeof a;
memset(a, 0, sizeof a); // zeroes out the array
The sizeof...
operator yields the number of elements in a parameter pack.
template <class... T>
void f(T&&...) {
std::cout << "f was called with " << sizeof...(T) << " arguments\n";
}
# Different keywords
void C++
void vobject; // C2182
void *pv; // okay
int *pint; int i;
int main() {
pv = &i;
// Cast optional in C required in C++
pint = (int *)pv;
Volatile C++
volatile declarator ;
virtual C++
virtual [type-specifiers] member-function-declarator
virtual [access-specifier] base-class-name
Parameters
this pointer
this->member-identifier
An object's this pointer is not part of the object itself; it is not reflected in the result of a sizeof statement on the object. Instead, when a nonstatic member function is called for an object, the address of the object is passed by the compiler as a hidden argument to the function. For example, the following function call:
myDate.setMonth( 3 );
can be interpreted this way:
setMonth( &myDate, 3 );
The object's address is available from within the member function as the this pointer. Most uses of this are implicit. It is legal, though unnecessary, to explicitly use this when referring to members of the class. For example:
void Date::setMonth( int mn )
{
month = mn; // These three statements
this->month = mn; // are equivalent
(*this).month = mn;
}
The expression *this is commonly used to return the current object from a member function:
return *this;
The this pointer is also used to guard against self-reference:
if (&Object != this) {
// do not execute in cases of self-reference
try, throw, and catch Statements (C++)
- To implement exception handling in C++, you use try, throw, and catch expressions.
- First, use a try block to enclose one or more statements that might throw an exception.
- A throw expression signals that an exceptional condition—often, an error—has occurred in a try block. You can use an object of any type as the operand of a throw expression. Typically, this object is used to communicate information about the error. In most cases, we recommend that you use the std::exception class or one of the derived classes that are defined in the standard library. If one of those is not appropriate, we recommend that you derive your own exception class from std::exception.
- To handle exceptions that may be thrown, implement one or more catch blocks immediately following a try block. Each catch block specifies the type of exception it can handle.
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
// The following syntax shows a throw expression
MyData GetNetworkResource()
{
// ...
if (IOSuccess == false)
throw networkIOException("Unable to connect");
// ...
if (readError)
throw myDataFormatException("Format error");
// ...
}
The code after the try clause is the guarded section of code. The throw expression throws—that is, raises—an exception. The code block after the catch clause is the exception handler. This is the handler that catches the exception that's thrown if the types in the throw and catch expressions are compatible.
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions – dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}
friend (C++)
class friend F
friend F;
class ForwardDeclared;// Class name is known.
class HasFriends
{
friend int ForwardDeclared::IsAFriend();// C2039 error expected
};
friend functions
#include <iostream>
using namespace std;
class Point
{
friend void ChangePrivate( Point & );
public:
Point( void ) : m_i(0) {}
void PrintPrivate( void ){cout << m_i << endl; }
private:
int m_i;
};
void ChangePrivate ( Point &i ) { i.m_i++; }
int main()
{
Point sPoint;
sPoint.PrintPrivate();
ChangePrivate(sPoint);
sPoint.PrintPrivate();
// Output: 0
1
}
Class members as friends
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
// A::Func1 is a friend function to class B
// so A::Func1 has access to all members of B
friend int A::Func1( B& );
};
int A::Func1( B& b ) { return b._b; } // OK
int A::Func2( B& b ) { return b._b; } // C2248
# Syntax
- asm (string-literal);
- noexcept(expression) // meaning 1
- noexcept(constant-expression) // meaning 2
- noexcept // meaning 2
- sizeof unary-expression
- sizeof(type-id)
- sizeof...(identifier) // since C++11
- typename nested-name-specifier identifier // meaning 1
- typename nested-name-specifier template(opt) simple-template-id // meaning 1
- typename identifier(opt) // meaning 2
- typename... identifier(opt) // meaning 2; since C++11
- typename identifier(opt) = type-id // meaning 2
- template <template-parameter-list> typename ...(opt) identifier(opt) // meaning 3
- template <template-parameter-list> typename identifier(opt) = id-expression // meaning 3
# Remarks
The full list of keywords is as follows:
alignas
(opens new window) (since C++11)alignof
(opens new window) (since C++11)asm
(opens new window)auto
: since C++11 (opens new window), before C++11 (opens new window)bool
(opens new window)break
(opens new window)case
(opens new window)catch
(opens new window)char
(opens new window)char16_t
(opens new window) (since C++11)char32_t
(opens new window) (since C++11)class
(opens new window)const
(opens new window)constexpr
(opens new window) (since C++11)const_cast
(opens new window)continue
(opens new window)decltype
(opens new window) (since C++11)default
(opens new window)delete
for memory management (opens new window), for functions (opens new window) (since C++11)do
(opens new window)double
(opens new window)dynamic_cast
(opens new window)else
(opens new window)enum
(opens new window)explicit
(opens new window)export
(opens new window)extern
as declaration specifier (opens new window), in linkage specification (opens new window), for templates (opens new window)false
(opens new window)float
(opens new window)for
(opens new window)friend
(opens new window)goto
(opens new window)if
(opens new window)inline
for functions (opens new window), for namespaces (opens new window) (since C++11), for variables (opens new window) (since C++17)int
(opens new window)long
(opens new window)mutable
(opens new window)namespace
(opens new window)new
(opens new window)noexcept
(opens new window) (since C++11)nullptr
(opens new window) (since C++11)operator
(opens new window)private
(opens new window)protected
(opens new window)public
(opens new window)register
(opens new window)reinterpret_cast
(opens new window)return
(opens new window)short
(opens new window)signed
(opens new window)sizeof
(opens new window)static
(opens new window)static_assert
(opens new window) (since C++11)static_cast
(opens new window)struct
(opens new window)switch
(opens new window)template
(opens new window)this
(opens new window)thread_local
(opens new window) (since C++11)throw
(opens new window)true
(opens new window)try
(opens new window)typedef
(opens new window)typeid
(opens new window)typename
(opens new window)union
(opens new window)unsigned
(opens new window)using
to redeclare a name (opens new window), to alias a namespace (opens new window), to alias a type (opens new window)virtual
for functions (opens new window), for base classes (opens new window)void
(opens new window)volatile
(opens new window)wchar_t
(opens new window)while
(opens new window)
The tokens final
and override
are not keywords. They may be used as identifiers and have special meaning only in certain contexts.
The tokens and
, and_eq
, bitand
, bitor
, compl
, not
, not_eq
, or
, or_eq
, xor
, and xor_eq
are alternative spellings of &&
, &=
, &
, |
, ~
, !
, !=
, ||
, |=
, ^
, and ^=
, respectively. The standard does not treat them as keywords, but they are keywords for all intents and purposes, since it is impossible to redefine them or use them to mean anything other than the operators they represent.
The following topics contain detailed explanations of many of the keywords in C++, which serve fundamental purposes such as naming basic types or controlling the flow of execution.