Inline variables
For now, it’s possible to specify variables as inline.
For example:
1 2 3 4 |
class B { public: inline static const int x{ 10 }; }; |
it allows keep it only in a header, without adding to cpp static variable.
constexpr variables have implicit inline.
structured bindings
Structured bindings allow more easy to use tuples. For example in C++14 to get tuple results:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class A { int x{ 10 }; int y{ 20 }; public: std::tuple<int, int> DoJob() { return std::tuple<int, int>(x, y); } }; int main() { A a; int x = 0; int y = 0; std::tie(x, y) = a.DoJob(); std::cout << x << " " << y << std::endl; return 0; } |
and in C++17, it will look like this:
1 2 3 4 5 6 7 8 |
int main() { A a; auto[x, y] = a.DoJob(); std::cout << x << " " << y << std::endl; return 0; } |
Looks much simpler.
Also, structured bindings work with arrays:
1 2 3 4 5 6 7 |
int main() { int x[] = { 1, 2, 3, 4 }; auto[a, b, c, d] = x; std::cout << a << b << c << d << std::endl; return 0; } |
Also, structured bindings work if class or struct have only non-static public members:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class A { public: int x{ 10 }; int y{ 20 }; }; int main() { A a; auto[x, y] = a; return 0; } |
Reference to tuple object:
1 |
auto& [a1, a2] = a.DoJob() |
Using structured bindings inside for loops:
1 2 3 4 |
for(auto& [key, value]: Somemap) { // ... } |
__has_include
Function macros which allow finding headers included in a compiler, because sometimes they can have a different path or be absent at all.
For example:
1 2 3 4 5 6 7 8 9 10 |
#if __has_include(<optional>) # include <optional> # define have_optional 1 #elif __has_include(<experimental/optional>) # include <experimental/optional> # define have_optional 1 # define experimental_optional 1 #else # define have_optional 0 #endif |
Attribute [[fallthrough]]
This attribute is used only inside switch statements, it used when fallthrough is expected and the compiler should not show warning about this.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int main() { int x = 2; switch (x) { case 1: [[fallthrough]]; case 2: break; default: break; } return 0; } |
Attribute [[nodiscard]]
This attribute is used when the value returned from function or method should not be discarded.
For example:
1 2 3 4 5 6 7 8 9 10 |
[[nodiscard]] int GetError() { return 1; } int main() { GetError(); return 0; } |
In this case, a compiler will show you the warning like this: discarding return value of function with ‘nodiscard‘ attribute.
To fix this, you need to check value which is marked as nodiscard.
For example:
1 |
int error = GetError(); |
Attribute [[maybe_unused]]
This attribute is used when warnings about unused need to be suppressed.
It can be used to suppress unused:
- variables
- typedefs
- static data members
- non-static data members
- enums
- functions
For example:
1 2 3 4 5 |
int main() { int x = 10; return 0; } |
in this case, compiler can show a warning like this: unused variable ‘x’ [-Wunused-variable]
To suppress warning you need add this attribute:
1 2 3 4 5 |
int main() { [[maybe_unused]]int x = 10; return 0; } |
std::launder
std::launder is used to get correct object represented by pointer within its lifetime.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct A { const int a; int b; }; int main() { A* a = new A{ 1, 2 }; A* aa = new(a) A{ 3, 4 }; const int x = a->a; // UB, because old object was destructed const int xx = std::launder(a)->a; // OK, points to new object return 0; } |
std::launder protects memory and variables from compiler optimization, that way object pointed from std::launder is valid.
std::byte type
std::byte was created to avoid issues with char, signed char, unsigned char. Because is char signed or unsigned, it’s compiler specific things.
std::byte is defined as:
1 |
enum class byte: unsigned char {}; |
std::byte can be used to access raw memory, but it’s not char type or integral byte. It’s just couple of bits.
Only bitwise operations are allowed.
For example, this code will not work:
1 2 3 |
std::byte byte{111}; byte = 10; // ERROR: no mathing operation |