I was C++ dev for 5 or 6 years, up to the late 2000s.

I got another C++ job about 3 years ago but bailed after about a year.

I could write a tome about what I dislike but to start with, any language that lacks a working standard built-in string type, is just a hard no for me at this stage in my life. Life is just too short.

The tooling and IDE support is atrocious, no standard dependency management for 3rd party libraries and CMake makes maven look well designed.

I tried to pull my knowledge up to date. Hmmm, we used to have lvalues and rvalues, what's this prvalue thing?

Surely cppreference can explain:

> a prvalue (“pure” rvalue) is an expression whose evaluation

> - computes the value of an operand of a built-in operator (such prvalue has no result object), or

> - initializes an object (such prvalue is said to have a result object).

> * The result object may be a variable, an object created by new-expression, a temporary created by temporary materialization, or a member thereof. Note that non-void discarded expressions have a result object (the materialized temporary). Also, every class and array prvalue has a result object except when it is the operand of decltype;*

> The following expressions are prvalue expressions:

> a literal (except for string literal), such as 42, true or nullptr;

> a function call or an overloaded operator expression, whose return type is non-reference, such as str.substr(1, 2), str1 + str2, or it++;

> a++ and a--, the built-in post-increment and post-decrement expressions;

> a + b, a % b, a & b, a << b, and all other built-in arithmetic expressions;

> a && b, a || b, !a, the built-in logical expressions;

> a < b, a == b, a >= b, and all other built-in comparison expressions;

> &a, the built-in address-of expression;

> a.m, the member of object expression, where m is a member enumerator or a non-static member function[2];

> p->m, the built-in member of pointer expression, where m is a member enumerator or a non-static member function[2];

> a.*mp, the pointer to member of object expression, where mp is a pointer to member function[2];

> p->*mp, the built-in pointer to member of pointer expression, where mp is a pointer to member function[2];

> a, b, the built-in comma expression, where b is an prvalue;

> a ? b : c, the ternary conditional expression for certain b and c (see definition for detail);

> a cast expression to non-reference type, such as static_cast<double>(x), std::string{}, or (int)42;

> the this pointer;

> an enumerator;

> a non-type template parameter of a scalar type;

> a lambda expression, such as [](int x){ return x * x; };

> (since C++11)

> a requires-expression, such as requires (T i) { typename T::type; };

> a specialization of a concept, such as std::equality_comparable<int>.

> (since C++20)

> Properties:

> Same as rvalue (below).

> A prvalue cannot be polymorphic: the dynamic type of the object it denotes is always the type of the expression.

> A non-class non-array prvalue cannot be cv-qualified, unless it is materialized in order to be bound to a reference to a cv-qualified type(since C++17). (Note: a function call or cast expression may result in a prvalue of non-class cv-qualified type, but the cv-qualifier is generally immediately stripped out.)

> A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier).

> A prvalue cannot have abstract class type or an array thereof.

Yeah, this language is loads of fun. I've worked on compilers, interpreters, implemented extended Hindley-Milner type systems, etc. so normally love reading formal language specs but this is just insane.