Supporting Extra Containers for Write Only
Good evening,
I tried looking around but couldn’t quite see what I’m looking for. I’m using absl::flat_hash_map and some other non standard containers. They all support standard iterator rules. How can I extend glaze to allow using these containers? I’m sure I have to be missing something simple.
[EDIT] I might close this. The problem isn’t the container, but likely with having a variant of std::unique_ptr. I’m trying to figure out a method to support inheritance. I figured a vector of unique_ptr might work, but need to likely just define a meta specialization.
So, this title is wrong, but if you’re okay keeping this issue open and providing input, that would be great. I’m trying to find a way to support inheritance within glaze. I know it doesn’t support inheritance until C++26 based off of some answers from 2023 and 2024 that I saw online.
My hierarchy is mostly flat.
Every “Site” has a SiteDiagnostic struct. It can be the base SiteDiagnostic or some optional more specific SiteDiagnostic that inherits from the base. This is the problem I’m trying to support.
This is what I’ve effectively tried so far… Again, I’m just trying to figure out a structure that Glaze likes that I can use to export custom types.
using SiteDiagnosticsTypes = std::tuple<SiteDiagnostic, DerivedSite0>; // more here, but this is the idea
template<typename T>
struct MakeVariantFromTuple;
template<typename… Types>
struct MakeVariantFromTuple<std::tuple<Types…>>
{
using type = std::variant<std::unique_ptr<Types>…>;
};
using SiteDiagnosticsVariant = MakeVariantFromTuple<SiteDiagnosticsTypes>::type;
absl::flat_hash_map<std::string, SiteDiagnosticsVariant>; // class member
You have an interesting type here, and the inheritance does make it more tricky. I would recommend using glz::to/glz::from specializations to make custom handling for your specific map type: absl::flat_hash_map<std::string, SiteDiagnosticsVariant>
Within the to/from specializations you can call other to/from internal code from Glaze, so you shouldn't need to much custom code.
Before I can give you a concrete examples, I would need to know how you plan to determine which variant type you intend to parse into.
Some important questions:
- Will the parser only allocate child types, or will it need to choose between whether to allocate a child or parent?
- Is the choice of the parent/child types in the variant dependent on a tagged field (e.g.
"type": "SiteDiagnostic"), or is the choice dependent upon the keys provided in the JSON object?
These are good questions.
So, the goal is to have a standard interface -- SiteDiagnostic -- the base class and then extensibility. For custom debugging, we need some sort of extension of the base. I'm using inheritance right now, but it could also be through composition if I can find a way to make it work. All of this to attempt to avoid the XY problem and give some context. Trying my best to keep glaze an implementation detail, and it is really nice when you can just use structures and not embed a glz::generic into SiteDiagnostic.
We probably would want the parser to allocate child types.
Right now, there's a factory registration method based off of a key. That key is stored in the JSON object. It's just a string in SiteDiagnostic that is effectively type. Named something else, but very similar in concept.
Here's another example I was trying. This is a minimal example. The idea here is to find a way to force a consistent base and reduce boilerplate, so I thought CRTP could be a solid approach. It inherits the base statically, and can also be extended pretty simply. Then, using an ID or ENUM as a tag can be useful if needed. However, this doesn't compile.
I have the latest pulled on my local personal and work machines. For Compiler Explorer, I'm just using whatever it thinks is trunk. I'm not sure if it's actually trunk or not.
Here's the link for compiler explorer: https://godbolt.org/z/v4o4snhrG
It's the same issue I have with the latest on my personal machine.
I'll give a more complete response when I have time, but Glaze currently supports std::variant of std::shared_ptr with auto deduction of the type based on the fields included in the JSON input.
std::unique_ptr is not supported right now because it requires the type to be copyable. I'll have to dig in and see if this requirement can be relaxed.
There are other ways this can be tackled, but I thought I'd let you know what is supported.
Ah. It seems to be a static variable that is causing the issue. I get errors on keys has to be compile time and get_name fails. As soon as I make type a regular member instance of a static member, things work again. This is with full enumeration of the types. There's pretty much no way around full enumeration, but it's nothing a macro can't fix. The static variable causes issues even without inheritance, at least from my examples I've been messing around with.
I actually have an example that successfully uses std::variant<std::unique_ptr<...>> that works as long as no static method is present.
enum struct Type {Base, Der0};
struct DiagBase {
virtual ~DiagBase() = default;
static constexpr auto type {Type::Base};
std::string name;
};
struct Der0: DiagBase {
static constexpr auto type {Type::Der0};
uint32_t der0Int {0};
};
I just merged in #2064, which adds better unique_ptr support and tagged id (type) variant support for types like unique_ptr and shared_ptr
I think everything you need is supported. See Variant Handling documentation for more details. If you have a specific issue, feel free to open another issue, but I'm going to close this one.
Glaze supports static constexpr fields if you add them to the glz::meta, but it also supports tag and ids in the glz::meta for your variant for decoding.