Move semantics makes value types cheap enough to pass around, so the default flips toward values: entities (identity, non-copyable) stay behind unique_ptr; everything else aspires to be a regular type.
struct Point { int x, y; };
class Connection {
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
};
No change in the model; relaxed constexpr quietly lets more value types live at compile time.
optional, variant and any make composed value types practical (sum and maybe types by value), and guaranteed elision lets factories return non-movable values.
using Shape = std::variant<Circle, Rect, Path>;
std::optional<Config> load(std::string_view path);
<=> plus std::regular make regularity cheap and nameable: default the comparisons, constrain templates on std::regular T, done.
struct Version {
int major{}, minor{}, patch{};
auto operator<=>(const Version&) = default;
};
static_assert(std::regular<Version>);
std::expected<T, E> extends the value-semantic style to fallible results — errors travel by value instead of by exception or out-param.
std::indirect / std::polymorphic remove the last big excuse for reference semantics in members: even heap-allocated and polymorphic state can now behave like a value (deep copy, deep const).
struct Node {
std::string name;
std::polymorphic<Expr> expr;
bool operator==(const Node&) const = default;
};
C++29direction · not adopted
Direction: pattern matching (P2688) would make consuming sum-typed values (variant, expected) first-class, strengthening the value-oriented style further.