Skip to content

Instantly share code, notes, and snippets.

@unrays
Created March 1, 2026 23:56
Show Gist options
  • Select an option

  • Save unrays/cfd820e12fe69fa552ede9fb8930bb84 to your computer and use it in GitHub Desktop.

Select an option

Save unrays/cfd820e12fe69fa552ede9fb8930bb84 to your computer and use it in GitHub Desktop.
Unfinished C++ mini-framework for type-safe JSON construction using CRTP, operator overloading, and generic lambdas.
// Copyright (c) March 2026 Félix-Olivier Dumas. All rights reserved.
// Licensed under the terms described in the LICENSE file
template<template<typename> class Res, template<typename> class Dis>
struct JsonBuildingPair {
template<typename T>
using Resolver = Res<T>;
template<typename T>
using Dispatcher = Dis<T>;
};
/********************************************************/
struct sentinel_t {};
inline constexpr sentinel_t sentinel{};
template<typename>
concept requires_derived = true;
struct parentheses;
struct subscript;
/***/
template<typename Operator, auto Behavior, typename CRTP_Context = void>
struct operator_wrapper;
template<auto Behavior>
struct operator_wrapper<parentheses, Behavior> {
template<typename... Args>
auto operator()(Args&&... args) {
return Behavior(std::forward<Args>(args)...);
}
};
template<auto Behavior, typename CRTP_Context>
struct operator_wrapper<parentheses, Behavior, CRTP_Context> {
template<typename... Args>
auto operator()(Args&&... args) {
return Behavior(
std::forward<Args>(args)...,
static_cast<CRTP_Context&>(*this)
);
}
};
/**/
template<auto Behavior>
struct operator_wrapper<subscript, Behavior> {
template<typename S = sentinel_t>
auto operator[](S&&) { return Behavior(); }
template<typename... Args>
auto operator[](Args&&... args) {
return Behavior(std::forward<Args>(args)...);
}
};
template<auto Behavior, typename CRTP_Context>
struct operator_wrapper<subscript, Behavior, CRTP_Context> {
template<typename S = sentinel_t>
auto operator[](S&&) { return Behavior(static_cast<CRTP_Context&>(*this)); }
template<typename... Args>
auto operator[](Args&&... args) {
return Behavior(
std::forward<Args>(args)...,
static_cast<CRTP_Context&>(*this)
);
}
};
/*********************************************************************/
struct JsonBuilderResolverTag {};
struct JsonBuilderDispatcherTag {};
/*********************************************************************/
template<typename OperatorTag, auto Behavior, typename CrtpContext>
struct JsonBuilderOperatorBase : operator_wrapper<OperatorTag, Behavior, CrtpContext> {};
/*********************************************************************/
constexpr auto NumberDispatcherBehavior =
[]<typename CrtpContext>(auto val, CrtpContext&& context) {
return context;
};
template<typename CrtpContext>
struct JsonBuilderNumberDispatcher : JsonBuilderDispatcherTag,
public JsonBuilderOperatorBase<parentheses, NumberDispatcherBehavior, CrtpContext>
{
using Base = JsonBuilderOperatorBase<parentheses, NumberDispatcherBehavior, CrtpContext>;
auto operator()(auto val) -> decltype(auto) { return Base::operator()(val); }
};
/*********************************************************************/
constexpr auto NumberResolverBehavior =
[]<typename CrtpContext>(CrtpContext&& context) {
return JsonBuilderNumberDispatcher<CrtpContext>{};
};
template<typename CrtpContext>
struct JsonBuilderNumberResolver : JsonBuilderResolverTag,
public JsonBuilderOperatorBase<subscript, NumberResolverBehavior, CrtpContext>
{
using Base = JsonBuilderOperatorBase<subscript, NumberResolverBehavior, CrtpContext>;
auto operator[](JSON_TAG_NUMBER) -> decltype(auto) { return Base::operator[](sentinel); }
};
/*********************************************************************/
constexpr auto TableResolverBehavior =
[]<typename CrtpContext>(CrtpContext&& context) {
std::cout << typeid(CrtpContext).name() << "\n";
std::cout << context.a << "\n";
return ChainResolverA{};
};
template<typename CrtpContext>
struct JsonBuilderTableResolver : JsonBuilderResolverTag,
public JsonBuilderOperatorBase<subscript, TableResolverBehavior, CrtpContext>
{
using Base = JsonBuilderOperatorBase<subscript, TableResolverBehavior, CrtpContext>;
auto operator[](JSON_TAG_TABLE) -> decltype(auto) { return Base::operator[](sentinel); }
};
/*********************************************************************/
template<template<typename> class... Resolvers>
struct JsonBuilderProxy2 : Resolvers<JsonBuilderProxy2<Resolvers...>>... {
using Resolvers<JsonBuilderProxy2<Resolvers...>>::operator[]...;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment