Skip to content

Why not also look inside the type for (static) to_json and from_json funtions? #511

@JoveToo

Description

@JoveToo

My knowledge of template magic is limited, so I'm probably missing something :).

Static member functions can access private and protected members.

class Type {
  ...
public:
    static void to_json(json &j, const Type &p) {...};
    static void from_json(json &j, Type &p) {...};
}

The main reason I see to declare these functions outside the scope of Type is to allow to separate serialization completely, which isn't possible because you always need the friends declaration, have getters/setters for all your internal variables or worse, have everything public.

I would even look inside Type for a serializer for std::shared_ptr<Type>.

In case a practical example helps, I am trying to serialize a template<Type> that contains map of std::shared_ptr<Type>.

// T::ptr_type is a typedef for std::shared_ptr<T>
template<typename T>
class Resolvable
{
public:
	typedef 	T	ref_type;
	Resolvable() {};
	Resolvable(ref_type r) : mReference(r) {};

	ref_type &Reference() {return mReference; };

protected:
	ref_type mReference;
};

template<typename T>
class Resolver {
public:
	Resolver()
	{
		// force T to be of Resolvable
		(void)static_cast<Resolvable<typename T::ref_type>*>((T*)0);
	}

	typename T::ptr_type &resolve(const typename T::ref_type &r)
	{
		return mEntries.at(r);
	}

	typename T::ref_type add(const typename T::ptr_type t)
	{
		typename T::ref_type r = static_cast<Resolvable<typename T::ref_type>*>(t.get())->Reference();
		if (mEntries.find(r) != mEntries.end())
			throw std::runtime_error("Duplicate entry " + std::to_string(r) + ".");

		mEntries[r] = t;

		return r;
	}

	void remove(const typename T::ref_type r)
	{
		mEntries.erase(r);
	}

	static void to_json(json &j, const Resolver<T> &resolver)
	{
		for(const std::pair<typename T::ref_type, typename T::ptr_type> &entry: resolver.mEntries)
		{
			j.push_back(*(entry.second));
		}
	};

	static void from_json(json &j, Resolver<T> &resolver)
	{
		for (json &e : j)
		{
			typename T::ptr_type ptr = std::make_shared<T>();
			T::from_json(e, *ptr);
			resolver.add(ptr);
		}
	};

private:
	std::map<typename T::ref_type, typename T::ptr_type>	mEntries;
};

The problem lies in the Resolver::from_json function: I can't find a way to express T::from_json(e, *ptr); in another way. If I do (*ptr) = e;, *ptr = e.get<T>() or ::from_json(e, *ptr);, it can't find the serialization function (and I run out of alternatives).

I have it all working by using static member functions and declaring external helpers that forward to the static ones. It works, it probably all gets optimized away, but it requires a lot of useless code.

If the serializer would check for those functions in the type, none of it would be necessary.

I realize there are probably other good solutions for my problem here (feel free to suggest them) but the static member function seems so simple a solution (for my problem at least) that I had to ask why this is not supported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind: enhancement/improvementstate: stalethe issue has not been updated in a while and will be closed automatically soon unless it is updated

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions