I'm actually working on a project I'm quite serious about but jokingly refer to as "Ergonomic Rust", which would make all of it a weird expression in Rust.
It's a C++23 library suite and lint set that eliminates:
- UB in all but the most contrived cases (I think I can get it to zero with a modest clang patch set)
- bounds errors (see below)
- bans all naked pointers and most references of any kind (NVRO and elision are mandated since 17, and on modern hardware like `znver5` you're usually pessimizing with e.g. `const foo_t& foo`)
- and has no `usafe` keyword to fall back on, that's enforced at the conceptual module level by having things declare they are unsafe in their entirety via `extern "C"`
It's a C++23 library suite and lint set that eliminates:
- UB in all but the most contrived cases (I think I can get it to zero with a modest clang patch set) - bounds errors (see below) - bans all naked pointers and most references of any kind (NVRO and elision are mandated since 17, and on modern hardware like `znver5` you're usually pessimizing with e.g. `const foo_t& foo`) - and has no `usafe` keyword to fall back on, that's enforced at the conceptual module level by having things declare they are unsafe in their entirety via `extern "C"`
This stuff is really unlocked by C++23:
``` template<typename T> concept SafeIndexable = requires(T& t, const T& ct, size_t idx) { { t.at(idx) } -> std::same_as<typename T::reference>; { ct.at(idx) } -> std::same_as<typename T::const_reference>; // Banned: t[idx] };
// Wrapper that forces .at() usage template<SafeIndexable Container> class Safe { Container c; public: // Forward everything except operator[] template<typename... Args> Safe(Args&&... args) : c(std::forward<Args>(args)...) {}
};// Usage: Safe<std::vector<int>> vec{1, 2, 3}; vec[10]; // Throws std::out_of_range instead of UB! ```