Skip to content

adl_serializer and CRTP #680

Closed
Closed

Description

@stevefan1999-personal

Because I really hate defining to_json/from_json by using the infamous ADL trick (I come from a C#/Java background so the fame of ADL depends), I decided to make the OOP-way-of-serialization shim of my own

I was having some progress, the following code demonstrated is a complete valid and legit code:

IJsonSerializable.hpp:

template<class T>
struct IJsonSerializable {
	using self_t = IJsonSerializable<T>;

	constexpr void to_json(json &j) const {
		auto self = const_cast<self_t *>(this);
		static_cast<T *>(self)->to_json(j);
	}

	constexpr void from_json(json &j) const {
		auto self = const_cast<self_t *>(this);
		static_cast<T *>(self)->from_json(j);
	}
};

template <class T>
constexpr void to_json(json &j, const IJsonSerializable<T> *value) {
	value->to_json(j);
}

template <class T>
constexpr void from_json(const json &j, IJsonSerializable<T> *value) {
	auto _j = const_cast<json &>(j);
	value->from_json(_j);
}

template <class T>
constexpr void to_json(json &j, const IJsonSerializable<T> &value) {
	value.to_json(j);
}

template <class T>
constexpr void from_json(const json &j, IJsonSerializable<T> &value) {
	auto _j = const_cast<json &>(j);
	value.from_json(_j);
}

Vector3.hpp:

#include "IJsonSerializable.h"

struct Vector3 : public IJsonSerializable<Vector3> {
	float x, y, z;

public:
	void to_json(json &j)  {
		j = { 
			{ "x", x }, 
			{ "y", y }, 
			{ "z", z} 
		};
	}

	void from_json(json &j) {
		x = j["x"];
		y = j["y"];
		z = j["z"];
	}
};

This works pretty much fine for me, but is there any way to rewrite it in the following form?

namespace nlohmann {
	template <class T>
	struct adl_serializer<IJsonSerializable<T>> { // not working, should I insert SFINAE here?
		using self_t = IJsonSerializable<T>;

		constexpr void to_json(json &j, const self_t *value) {
			value->to_json(j);
		}

		constexpr void from_json(const json &j, self_t *value) {
			auto _j = const_cast<json &>(j);
			value->from_json(_j);
		}

		constexpr void to_json(json &j, const self_t &value) {
			value.to_json(j);
		}

		constexpr void from_json(const json &j, self_t &value) {
			auto _j = const_cast<json &>(j);
			value.from_json(_j);
		}
	};
}

I group all my other serializers into namespace nlohmann just to keep it away from polluting my global namespace without creating another namespace of my own.

Activity

  1. theodelrieu commented on Aug 8, 2017

    @theodelrieu
    Contributor

    I'll take a look once I arrive to work, what if you replace self_t* with a reference?

    We do not support pointers in from/to_json at the moment.

    EDIT: also you must declare adl_serializer methods as static, it will not work otherwise.

  2. theodelrieu commented on Aug 12, 2017

    @theodelrieu
    Contributor

    Hi, just checking back, the code works on my laptop when adding static in front of both methods.

    By the way, you can remove both overloads that take self_t *, they will never be called by the library.

  3. nlohmann commented on Aug 15, 2017

    @nlohmann
    Owner

    Can I close this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    solution: proposed fixa fix for the issue has been proposed and waits for confirmation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions