-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Description
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.