# Variable Declaration Keywords
# decltype
Yields the type of its operand, which is not evaluated.
int x = 42;
std::vector<decltype(x)> v(100, x); // v is a vector<int>
struct S {
int x = 42;
};
const S s;
decltype(s.x) y; // y has type int, even though s.x is const
-
- If `e` is an lvalue of type `T`, then `decltype(e)` is `T&`.
- If `e` is an xvalue of type `T`, then `decltype(e)` is `T&&`.
- If `e` is a prvalue of type `T`, then `decltype(e)` is `T`.
- When used alone,
int
is implied, so thatsigned
,signed int
, andint
are the same type. - When combined with
char
, yields the typesigned char
, which is a different type fromchar
, even ifchar
is also signed.signed char
has a range that includes at least -127 to +127, inclusive. - When combined with
short
,long
, orlong long
, it is redundant, since those types are already signed. signed
cannot be combined withbool
,wchar_t
,char16_t
, orchar32_t
.- When used alone,
int
is implied, sounsigned
is the same type asunsigned int
. - The type
unsigned char
is different from the typechar
, even ifchar
is unsigned. It can hold integers up to at least 255. unsigned
can also be combined withshort
,long
, orlong long
. It cannot be combined withbool
,wchar_t
,char16_t
, orchar32_t
.
This includes the case with extraneous parentheses.
int f() { return 42; }
int& g() { static int x = 42; return x; }
int x = 42;
decltype(f()) a = f(); // a has type int
decltype(g()) b = g(); // b has type int&
decltype((x)) c = x; // c has type int&, since x is an lvalue
The special form decltype(auto)
deduces the type of a variable from its initializer or the return type of a function from the return
statements in its definition, using the type deduction rules of decltype
rather than those of auto
.
const int x = 123;
auto y = x; // y has type int
decltype(auto) z = x; // z has type const int, the declared type of x
# const
A type specifier; when applied to a type, produces the const-qualified version of the type. See const keyword (opens new window) for details on the meaning of const
.
const int x = 123;
x = 456; // error
int& r = x; // error
struct S {
void f();
void g() const;
};
const S s;
s.f(); // error
s.g(); // OK
# signed
A keyword that is part of certain integer type names.
Example:
signed char celsius_temperature;
std::cin >> celsius_temperature;
if (celsius_temperature < -35) {
std::cout << "cold day, eh?\n";
}
# unsigned
A type specifier that requests the unsigned version of an integer type.
Example:
char invert_case_table[256] = { ..., 'a', 'b', 'c', ..., 'A', 'B', 'C', ... };
char invert_case(char c) {
unsigned char index = c;
return invert_case_table[index];
// note: returning invert_case_table[c] directly does the
// wrong thing on implementations where char is a signed type
}
# volatile
A type qualifier; when applied to a type, produces the volatile-qualified version of the type. Volatile qualification plays the same role as const
qualification in the type system, but volatile
does not prevent objects from being modified; instead, it forces the compiler to treat all accesses to such objects as side effects.
In the example below, if memory_mapped_port
were not volatile, the compiler could optimize the function so that it performs only the final write, which would be incorrect if sizeof(int)
is greater than 1. The volatile
qualification forces it to treat all sizeof(int)
writes as different side effects and hence perform all of them (in order).
extern volatile char memory_mapped_port;
void write_to_device(int x) {
const char* p = reinterpret_cast<const char*>(&x);
for (int i = 0; i < sizeof(int); i++) {
memory_mapped_port = p[i];
}
}