...or the monster that C++ has become.
C++ reinvented itself during the last years, and is barely recognizable now from the good old C++98. It's not like C++ was a simple language back then - quite the contrary. But on top of all this, so many new features have been added that it has become a monster.
And generally speaking, this is a good thing: You now have smart pointers, lambdas, ranges, a chrono library, threads, concepts, modules and so much more. But it can become quite overwhelming with all that new language features additionally. So I created a short overview with a quick (mostly) self explanatory examples, of some of features you might have missed:
| Auto |
auto a = 4 + 6; |
| Lambdas |
auto aLambda = [](auto a, auto b)
{ return a < b; };
bool b = aLambda(5, 1.23);
|
| Strongly typed enums |
enum class
{
value1,
value2
}; |
| Static assert |
static_assert( sizeof(x) == 4 ); |
| Range based for |
for (auto x : arr)
{
foo(x);
} |
| Type alias |
using IntVector = std::vector; |
| Unicode strings |
const char* utf8 = u8"foo";
const char16_t* utf16 = u"bar";
const char32_t* utf32 = U"baz"; |
| Move and move contructors |
struct X
{
std::string str;
X(): str("foo") { }
X(const X& b) : str(b.str) { }
X(X&& b) noexcept : str(std::move(b.str)) { }
}; |
| override |
struct A
{
virtual void foo() {};
};
struct B : public A
{
void foo() override {};
}; |
| Designated initializers |
struct A { int x; int y; int z; };
A a { .x = 1, .z = 2 }; |
| Modules |
import someModule;
// now use features from that module |
| Range based for with init |
int arr[255];
for (int c = 0; auto& x : arr)
{
foo(x, c); ++c;
} |
| Auto returns |
auto func(int n)
{
return n + 1;
} |
| Consteval |
static consteval int sqr(int n)
{
return n * n;
} |
| Constinit |
constinit auto sqrOf5 = sqr(5); |
| Concepts |
template
concept IsComparable = requires(T a, T b) {
{ a == b } -> std::same_as;
{ a != b } -> std::same_as;
};
class myclass {
void func(const IsComparable auto& a) { };
}; |
| If with initializer |
if (auto p = foobar(); p->value > 1)
{
printf("no");
} |
| Switch with initializer |
switch (auto p = foobar(); auto x = p->value)
{
case 0: printf("yes"); break;
case 1: printf("no"); break;
} |
| Constexpr if |
if constexpr (sizeof(int) == 1)
return 0; |
| Auto template parameters |
template class someclass
{
static auto TConstant = value;
}; |
| Space ship operator |
auto operator<=>(const a&) const = default; |
| Nested namespace definitions |
namespace A::B::C
{
class myclass { };
} |
| Inline variables |
class ClassWithInlineVariable
{
static inline int field = 42;
}; |
| Trailing return type |
auto foo(int p) -> int { return p * 42; } |
| Decltype |
int n = 33;
decltype(n) t = n+4; |
| Structured binding |
int arr[3] = {3,4,5};
auto [x,y,z] = arr;
|
| Namespaces with attributes |
namespace [[someAttribute]] myNamespace
{
}; |
| Enumerators with attributes |
enum class myEnum
{
value1 [[anAttribute]],
value2 [[anotherAttribute]] = 3
}; |