C++ - Reddit
229 subscribers
48 photos
8 videos
1 file
25.5K links
Stay up-to-date with everything C++!
Content directly fetched from the subreddit just for you.

Join our group for discussions : @programminginc

Powered by : @r_channels
Download Telegram
"override members" idea as a gateway to UFCS (language evolution)

(UFCS backgrounder: https://isocpp.org/files/papers/N4174.pdf )

I have two functions that tell me if a string contains the
characters of a particular integer. They're called hasInt and intIn.
(intIn is inspired by the python keyword in.)
They looks like this:

bool hasInt(const string s, int n)// does s have n?
{
return s.contains(tostring(n));
}

bool intIn(int n, const string s)// is n in s?
{
return s.contains(to
string(n));
}

It would be convenient if I could add hasInt as a member function to std::string:

bool string::hasInt(int n)
{
return ::hasInt(this, n);
}

Then I could use "member syntax" to call the function, like `text.hasInt(123)`.

Of course, that's not possible, because then I'd be changing the header files
in the standard libraries.

Here's an idea for a new language feature:
let's use the `override` keyword to allow us to "inject" member functions
into an existing class, without modifying the class definition. So the code:

override bool string::hasInt(int n)
{
return ::hasInt(
this, n);
}

will (in effect) add hasInt as a member function to string.

Thus, this "override member function" feature has a syntax like:

ReturnType ClassName::function(args){...etc...}

HOWEVER..... what if ClassName doesn't necessarily need to be a class, and could be
other types? Then you open the door to override members like:

override bool int::intIn(const string s)
{
return ::intIn(this, s);
}

Which allows code like `(123).intIn(text)`.

This is halfway to UFCS!

Using some macro magic and helper templates, we could define a
MAKE_UFCS macro to convert a non-member function into a member function:

#define MAKE_UFCS(f) \
override \
retType(f) argType1(f)::f(argType2(f) x)\
{ \
return f(
this, x); \
}

Thus the non-member functions hasInt and intIn could be "opted in" to UFCS
by the macro calls:

MAKEUFCS(hasInt);
MAKE
UFCS(intIn);

Or maybe, if this override-to-UFCS is useful enough, the override feature can be
applied to a collection of functions at once, like:

override hasInt, intIn;

or

override {
#include <cstdlib>
}

To UFCS-ify an entire header file at the same time.

EDIT: this idea would be similar to Scala's "Extension Methods": https://docs.scala-lang.org/scala3/book/ca-extension-methods.html

or C#'s "Extension Members": https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

https://redd.it/1qyikcg
@r_cpp
MigrationManager::GetInstance();
manager.CreateMigrationHistory();
size_t applied = manager.ApplyPendingMigrations();
```

Supports rollbacks, dry-run preview, checksum verification, and distributed locking for safe concurrent deployments.

---

## Backup & Restore

Full database backup/restore with progress reporting:

```cpp
#include <Lightweight/SqlBackup.hpp>

// Backup to compressed archive (multi-threaded)
SqlBackup::Backup(
"backup.zip",
connectionString,
4, // concurrent workers
progressManager,
"", // schema
"*", // table filter (glob)
{}, // retry settings
{ .method = CompressionMethod::Zstd, .level = 6 }
);

// Restore
SqlBackup::Restore("backup.zip", connectionString, 4, progressManager);
```

Preserves indexes, foreign keys (including composite), and supports table filtering.

---

## Supported Databases

- Microsoft SQL Server
- PostgreSQL
- SQLite3

Works anywhere ODBC works (Windows, Linux, macOS).

---

## What's Next

We're actively developing and would love feedback. The library is production-ready for our use cases, but we're always looking to improve the API and add features.

We also consider abstracting away ODBC such that it could support non-ODBC databases like SQLite3 directly without the ODBC layer. That's a longer-term goal, but definitely a goal.

We currently focus on SQL tooling (migrations and backup/restore) as both are quite young additions that are still evolving.

Questions and PRs welcome!

https://redd.it/1r0co80
@r_cpp
Corosio Beta - coroutine-native networking for C++20

We are releasing the Corosio beta - a coroutine-native networking library for C++20 built by the C++ Alliance. It is the successor to Boost.Asio, designed from the ground up for coroutines.

**What is it?**

Corosio provides TCP sockets, acceptors, TLS streams, timers, and DNS resolution. Every operation is an awaitable. You write co\_await and the library handles executor affinity, cancellation, and frame allocation. No callbacks. No futures. No sender/receiver.

It is built on Capy, a coroutine I/O foundation that ships with Corosio. Capy provides the task types, buffer sequences, stream concepts, and execution model. The two libraries have no dependencies outside the standard library.

**An echo server in 45 lines:**

#include <boost/capy.hpp>
#include <boost/corosio.hpp>

namespace corosio = boost::corosio;
namespace capy = boost::capy;

capy::task<> echo_session(corosio::tcp_socket sock)
{
char buf[1024];
for (;;)
{
auto [ec, n] = co_await sock.read_some(
capy::mutable_buffer(buf, sizeof(buf)));

auto [wec, wn] = co_await capy::write(
sock, capy::const_buffer(buf, n));

if (ec)
break;
if (wec)
break;
}
sock.close();
}

capy::task<> accept_loop(
corosio::tcp_acceptor& acc,
corosio::io_context& ioc)
{
for (;;)
{
corosio::tcp_socket peer(ioc);
auto [ec] = co_await acc.accept(peer);
if (ec)
continue;
capy::run_async(ioc.get_executor())(echo_session(std::move(peer)));
}
}

int main()
{
corosio::io_context ioc;
corosio::tcp_acceptor acc(ioc, corosio::endpoint(8080));
capy::run_async(ioc.get_executor())(accept_loop(acc, ioc));
ioc.run();
}

**Features:**

* Coroutine-only - every I/O operation is an awaitable, no callbacks
* TCP sockets, acceptors, TLS streams, timers, DNS resolution
* Cross-platform: Windows (IOCP), Linux (epoll), macOS/FreeBSD (kqueue)
* Type-erased streams - write any\_stream& and accept any stream type. Compile once, link anywhere. No template explosion.
* Zero steady-state heap allocations after warmup
* Automatic executor affinity - your coroutine always resumes on the right thread
* Automatic stop token propagation - cancel at the top, everything below stops Buffer sequences with byte-level manipulation (slice, front, consuming\_buffers, circular buffers)
* Concurrency primitives: strand, thread\_pool, async\_mutex, async\_event, when\_all, when\_any Forward-flow allocator control for coroutine frames
* C++20: GCC 12+, Clang 17+, MSVC 14.34+

**Get it:**

git clone https://github.com/cppalliance/corosio.git
cd corosio
cmake -S . -B build -G Ninja
cmake --build build

No dependencies. Capy is fetched automatically.

Or use CMake FetchContent in your project:

include(FetchContent)
FetchContent_Declare(corosio
GIT_REPOSITORY https://github.com/cppalliance/corosio.git
GIT_TAG develop
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(corosio)
target_link_libraries(my_app Boost::corosio)

**Links:**

* Corosio: [https://github.com/cppalliance/corosio](https://github.com/cppalliance/corosio)
* Corosio docs: [https://develop.corosio.cpp.al/](https://develop.corosio.cpp.al/)
* Capy: [https://github.com/cppalliance/capy](https://github.com/cppalliance/capy)
* Capy docs: [https://develop.capy.cpp.al/](https://develop.capy.cpp.al/)

**What’s next:**

HTTP, WebSocket, and high-level server libraries are in development on the same foundation. Corosio is heading for Boost formal review. We want your feedback.

https://redd.it/1rqykml
@r_cpp
Modern declarative EDSL for graphic user interface in C++? Not QML or XAML.

Hello everyone,

I have been investigating lately (after using NiceGUI for a real project) and learning Jetpack Compose (not writing any real code with it, would do it with Jetpack Multiplatform if ever).

I am really impressed by Jetpack Compose approach, especially UDF.

I thought there could possibly not be a better way than MVVM tbh, after using it for years.

But after seeing how declarative composition inside the language, not with XAML or QML can be done, I am sold in the amount of boilerplate that can be saved, plus the better integration when the dsl is in the host language.

So I wanted to mention I found this, which I think could be a good start for some experiments, on top of wxWidgets: https://github.com/rmpowell77/wxUI

I think it has a talk in CppCon2025 here: https://www.youtube.com/watch?v=xu4pI72zlO4

Kudos to the author for bringing something like this to C++! Definitely useful.

I would like to hear your opinions on this style of EDSL GUI embedding and pros/cons you find for those of you who do GUI programming all the time.

Also, wild idea: with the power of compile-time C++ programming and C++26 reflection, it would be possible to get existing xaml interfaces and convert it into regular C++ at compile-time via #embed or #include and not even changing the EDSL itself and making it directly embedded and reusable in C++? That would be plenty useful.


https://redd.it/1ry51fg
@r_cpp
I built a C++ integer-to-string library based on a new AVX-512 paper

I built a small C++ integer-to-string conversion library based on a new paper by Jael Champagne Gareau and Daniel Lemire, "Converting an Integer to a Decimal String in Under Two Nanoseconds":

- Project: https://github.com/simditoa/simditoa
- Paper: https://arxiv.org/abs/2604.26019

The paper looks at decimal formatting for integers, which shows up in logging, JSON/CSV/XML serialization, database output, and other places where numbers eventually become text. The interesting part, and the part I wanted to experiment with, is that it uses AVX-512 IFMA instructions to extract multiple decimal digits in parallel, avoiding the usual repeated division/modulo loop and avoiding large lookup tables.

The library exposes a small to_chars-style API:

#include "simditoa.h"

char buf[simditoa::MAX_DIGITS + 1];
size_t len = simditoa::to_chars(12345, buf);
buf[len] = '\0';


Current project shape:

- C++17
- int64_t and uint64_t support
- AVX-512 IFMA + VBMI path for supported x86-64 CPUs
- portable scalar fallback
- CMake package/install support
- tests for edge cases, digit lengths, and randomized values
- a simple benchmark against std::to_chars

The README benchmark currently shows simditoa::to_chars at about 15.82 ns/int versus 36.35 ns/int for std::to_chars on the tested setup, roughly 2.3x faster in that run. The paper reports stronger results for its full algorithm and benchmark suite, including single-core performance ahead of other tested methods, but my repo should be treated as a compact implementation based on the paper rather than a full reproduction of every variant in it.

The core trick is neat: for 8-digit chunks, it uses AVX-512 IFMA with precomputed constants based on floor(2^52 / 10^k) to compute digit positions in parallel, then gathers the digit bytes with AVX-512 byte permutation. Larger values are split into chunks.


https://redd.it/1t2ny62
@r_cpp
Are you satisfied with the current state of C++ CLI parsers?

There are already many excellent C++ CLI parsers out there, but most of them still revolve around mutable runtime builder APIs.

Most existing parsers look something like this:

CLI::App app{"example"};

std::string output;
bool verbose = false;
std::vector<std::string> inputs;

app.add_option("-o,--output", output, "output file");
app.add_flag("-v,--verbose", verbose, "verbose mode");
app.add_option("inputs", inputs, "input files")->required();

CLI11_PARSE(app, argc, argv);

Why are duplicate option names still runtime errors in C++ CLI parsers? Where is the compile-time validation?

Why is the command schema still built through runtime mutation? Many CLI schemas are effectively static. Why not treat them as a static schema and let the compiler enforce it?

One of the things I love about C++ is its ability to express intent and constraints in the type system and let the compiler enforce them.

But many C++ CLI parsers still rely heavily on runtime mutation and stringly-typed APIs.

Rust has `clap`, which is a great typed CLI parser. So what about C++?

So I wanted to explore what that direction could look like in modern C++20.

**I built a new C++ CLI parser** that takes a different approach:

#include <cli/cli.hh>

struct Args {
cli::Flag<"verbose", 'v'> verbose;
cli::StringOption<"output", 'o'> output;
cli::Positional<std::string, cli::nargs::one_or_more> inputs;
};

using namespace std;

auto main(int argc, char** argv) -> int {
// Returns parsed Args or exits with an error message.
const auto args = cli::parseOrExit<Args>(argc, argv);

std::cout << "verbose: " << args.verbose.value() << '\n';

if (args.output.has_value()) {
std::cout << "output: " << *args.output.value() << '\n';
}

for (const auto& input : args.inputs.value()) {
std::cout << input << '\n';
}
}

**Try this out on Godbolt:** [https://godbolt.org/z/53d8rEMoP](https://godbolt.org/z/53d8rEMoP)

The goal is to explore a C++20-native parser API where the command line is represented as a typed schema rather than a mutable runtime builder.

The interesting part for me is that this works in **plain C++20**, without reflection, macros, code generation, or external tooling.

Repository: [https://github.com/CLI20-dev/cli20](https://github.com/CLI20-dev/cli20)

Still early-stage. I'm mainly looking for feedback on API ergonomics, diagnostics, and the compile-time/runtime tradeoff.

https://redd.it/1t5fovs
@r_cpp
Poor man's defineaggregate

TLDR: [Try it on Compiler Explorer](
https://godbolt.org/z/sfczoP7hr).

----

While waiting for Clang to support `define
aggregate, I got curious about whether it's possible to do something similar in C++23. Turns out it *kinda* is.

### Rules:
- Only C++23 features;
- No external programs;
- No macros;
- Generated code should be similar to just using a
struct.

----

We start with some helper types:

#include <algorithm>
#include <array>
#include <concepts>
#include <functional>
#include <print>
#include <ranges>
#include <string_view>
#include <tuple>
#include <type_traits>

namespace detail
{

// See
type
template <typename T>
struct FieldType
{
using Type = T;
};

// Helper for using a string as a template parameter
template <std::size_t size>
struct ConstexprStringHelper
{
std::array<char, size - 1> array;

constexpr ConstexprStringHelper(const char (&c_array)[size])
{
std::copy_n(c_array, size - 1, std::begin(array));
}
};

// See
operator""field`
template <auto name>
struct FieldByName
{
};

We calculate the layout of our fake aggregate (sizes, alignment, offsets, ...) at compile time, like so:

// Layout information
template <auto... fields>
struct MetaAggregateInfo
{
static consteval auto calc
align(std::sizet offset, std::sizet align)
{
return (offset + align - 1) & ~(align - 1);
}

static constexpr std::array names{ std::stringview(fields.name)... };
static constexpr std::array sizes{ sizeof(typename decltype(fields)::Type)... };
static constexpr std::array aligns{ alignof(typename decltype(fields)::Type)... };
static constexpr auto max
align = std::ranges::max(aligns);
static constexpr auto offsets = {
std::removeconstt<decltype(sizes)> offsets;
std::sizet nextoffset = 0;

for (auto size, align, offset : std::views::zip(sizes, aligns, offsets))
{
offset = calcalign(nextoffset, align);
nextoffset = offset + size;
}

return offsets;
}();
static constexpr auto total
size = calcalign(offsets.back() + sizes.back(), maxalign);
};

I found it simpler to just use a partial specialization for the case where the aggregate has no members:

template <>
struct MetaAggregateInfo<>
{
static constexpr std::array<std::stringview, 0> names{};
static constexpr std::array<std::size
t, 0> sizes{};
static constexpr std::array<std::sizet, 0> aligns{};
static constexpr auto max
align = 1uz;
static constexpr std::array<std::sizet, 0> offsets{};
static constexpr auto total
size = 1uz;
};

}

A few more helpers:

// Use to declare the type of a field. See example below.
template <typename T>
constexpr detail::FieldType<T> type;

// Type and name of a field
template <typename TheType, std::sizet size>
struct Field
{
using Type = TheType;

detail::FieldType<TheType> type;
std::array<char, size> name;
};

// Use to declare the name of a field
template <detail::ConstexprStringHelper helper>
consteval auto operator""
name()
{
return helper.array;
}

// Use with operator to access a field by name
template <detail::ConstexprStringHelper helper>
consteval auto operator""field() -> detail::FieldByName<helper.array>
{
return {};
}

And now the meat of the code:

template <auto... fields>
class MetaAggregate
{
public:
static constexpr detail::MetaAggregateInfo<fields...> info{};

We define our constructors, copy/move operators and destructor. We use the offsets to get a pointer on which we can do a placement `new`. Other than that, this part is not very interesting.

MetaAggregate()
requires(std::default
initializable<typename decltype(fields)::Type> && ...)
{
std::apply(
& { (new (storage.data() + offset) decltype(fields)::Type(), ...); },
info.offsets
);
}

MetaAggregate(const MetaAggregate& other)
requires(std::copyconstructible<typename decltype(fields)::Type> && ...)
: MetaAggregate(other.refs())
{
}

MetaAggregate(MetaAggregate&& other)
requires(std::move
constructible<typename
Poor man's define_aggregate

TLDR: [Try it on Compiler Explorer](https://godbolt.org/z/sfczoP7hr).

----

While waiting for Clang to support `define_aggregate`, I got curious about whether it's possible to do something similar in C++23. Turns out it *kinda* is.

### Rules:
- Only C++23 features;
- No external programs;
- No macros;
- Generated code should be similar to just using a `struct`.

----

We start with some helper types:

#include <algorithm>
#include <array>
#include <concepts>
#include <functional>
#include <print>
#include <ranges>
#include <string_view>
#include <tuple>
#include <type_traits>

namespace detail
{

// See `type`
template <typename T>
struct FieldType
{
using Type = T;
};

// Helper for using a string as a template parameter
template <std::size_t size>
struct ConstexprStringHelper
{
std::array<char, size - 1> array;

constexpr ConstexprStringHelper(const char (&c_array)[size])
{
std::copy_n(c_array, size - 1, std::begin(array));
}
};

// See `operator""_field`
template <auto name>
struct FieldByName
{
};

We calculate the layout of our fake aggregate (sizes, alignment, offsets, ...) at compile time, like so:

// Layout information
template <auto... fields>
struct MetaAggregateInfo
{
static consteval auto calc_align(std::size_t offset, std::size_t align)
{
return (offset + align - 1) & ~(align - 1);
}

static constexpr std::array names{ std::string_view(fields.name)... };
static constexpr std::array sizes{ sizeof(typename decltype(fields)::Type)... };
static constexpr std::array aligns{ alignof(typename decltype(fields)::Type)... };
static constexpr auto max_align = std::ranges::max(aligns);
static constexpr auto offsets = [] {
std::remove_const_t<decltype(sizes)> offsets;
std::size_t next_offset = 0;

for (auto [size, align, offset] : std::views::zip(sizes, aligns, offsets))
{
offset = calc_align(next_offset, align);
next_offset = offset + size;
}

return offsets;
}();
static constexpr auto total_size = calc_align(offsets.back() + sizes.back(), max_align);
};

I found it simpler to just use a partial specialization for the case where the aggregate has no members:

template <>
struct MetaAggregateInfo<>
{
static constexpr std::array<std::string_view, 0> names{};
static constexpr std::array<std::size_t, 0> sizes{};
static constexpr std::array<std::size_t, 0> aligns{};
static constexpr auto max_align = 1uz;
static constexpr std::array<std::size_t, 0> offsets{};
static constexpr auto total_size = 1uz;
};

}

A few more helpers:

// Use to declare the type of a field. See example below.
template <typename T>
constexpr detail::FieldType<T> type;

// Type and name of a field
template <typename TheType, std::size_t size>
struct Field
{
using Type = TheType;

detail::FieldType<TheType> type;
std::array<char, size> name;
};

// Use to declare the name of a field
template <detail::ConstexprStringHelper helper>
consteval auto operator""_name()
{
return helper.array;
}

// Use with operator[] to access a field by name
template <detail::ConstexprStringHelper helper>
consteval auto operator""_field() -> detail::FieldByName<helper.array>
{
return {};
}

And now the meat of the code:

template <auto... fields>
class MetaAggregate
{
public:
static constexpr detail::MetaAggregateInfo<fields...> info{};

We define our constructors, copy/move operators and destructor. We use the offsets to get a pointer on which we can do a placement `new`. Other than that, this part is not very interesting.

MetaAggregate()
requires(std::default_initializable<typename decltype(fields)::Type> && ...)
{
std::apply(
[&](auto... offset) { (new (storage.data() + offset) decltype(fields)::Type(), ...); },
info.offsets
);
}

MetaAggregate(const MetaAggregate& other)
requires(std::copy_constructible<typename decltype(fields)::Type> && ...)
: MetaAggregate(other.refs())
{
}

MetaAggregate(MetaAggregate&& other)
requires(std::move_constructible<typename
fluxen: a single-header key-value store for C++20

I built fluxen to solve a problem I kept running into in my side projects. I wanted persistent key-value storage without pulling in a full database or dealing with CMake/linking.

To use fluxen, you just drop the header into your project and you have a persistent key-value database that you can learn to use in an afternoon, with no CMake, no dependencies, and no linking.

#include "fluxen.hpp"

fluxen::DB db("myapp.db");
db.put("username", "jim");

if (auto name = db.get("username")) {
std::cout << *name << "\n"; // jim
}

It supports strings, numbers, and any trivially copyable type without the need for manual serialization. Transactions batch writes into a single syscall and guarantee durability via fsync.

GitHub: [https://github.com/dvuvud/fluxen](https://github.com/dvuvud/fluxen)

Docs: [https://dvuvud.github.io/fluxen](https://dvuvud.github.io/fluxen)

https://redd.it/1t928n5
@r_cpp