Sean Parent "Runtime Polymorphism"的动机我实现了一个Serializable
类,它使用类型擦除来发送Serializable::serialize(...)
⟶obj.serialize(...)
,其中obj
是一个包装对象
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T>
class Model final : public Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
private:
std::unique_ptr<Concept> m_self;
};
现在我想将Serializable
扩展为另一个模型类,它将Serializable::serialize(...)
发送到以obj
为参数的自由函数:Serializable::serialize(...)
⟶{{1} }
然后我希望serialize(obj, ...)
的模板构造函数通过检查Serializable
或T::serialize(...)
是否可以通过任何方式(例如,SFINAE)自动构造serialize(const T&, ...)
,以便在可能的情况下使用方法序列化,否则使用自由函数序列化?
随意使用C ++ 17以外的任何C ++标准。
答案 0 :(得分:2)
您可以设计自己的特质,以确定该班级是否具有正确的serialize
成员。有几种方法可以做到这一点,其中之一是:
template <class T, class = void>
struct HasMemberSerialize : std::false_type
{};
template <class T>
struct HasMemberSerialize<T, std::void_t<decltype(std::declval<T>().serialize(std::declval<Storage&>()))>> : std::true_type
{};
然后,将新模板参数添加到Model
并使用特征查找其参数:
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T, HasMemberSerialize<T>::value> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T, bool Member>
class Model;
private:
std::unique_ptr<Concept> m_self;
};
template <typename T>
class Serializable::Model<T, true> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
template <typename T>
class Serializable::Model<T, false> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ serialize(m_data, outStream); }
private:
T m_data;
};