基于方法或自由函数的存在的模板构造函数解析
Template constructor resolution based on existence of method or free-function
问题
受到 Sean Parent 的 "Runtime Polymorphism" 的启发,我实现了一个 Serializable
class,它使用类型擦除来调度 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;
};
现在我想用另一个模型 class 扩展 Serializable
,它将 Serializable::serialize(...)
分派给一个以 obj
作为参数的自由函数:Serializable::serialize(...)
⟶ serialize(obj, ...)
然后我想要 Serializable
的模板构造函数通过检查 T::serialize(...)
或 serialize(const T&, ...)
的存在来决定使用哪个模型
问题
是否可以通过任何方式(例如 SFINAE)自动构建 Serializable
,以便它尽可能使用方法序列化,否则使用自由函数序列化?
随意使用 C++17 之前的任何 C++ 标准。
您可以设计自己的特征来查明 class 是否具有正确的 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;
};
问题
受到 Sean Parent 的 "Runtime Polymorphism" 的启发,我实现了一个 Serializable
class,它使用类型擦除来调度 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;
};
现在我想用另一个模型 class 扩展 Serializable
,它将 Serializable::serialize(...)
分派给一个以 obj
作为参数的自由函数:Serializable::serialize(...)
⟶ serialize(obj, ...)
然后我想要 Serializable
的模板构造函数通过检查 T::serialize(...)
或 serialize(const T&, ...)
问题
是否可以通过任何方式(例如 SFINAE)自动构建 Serializable
,以便它尽可能使用方法序列化,否则使用自由函数序列化?
随意使用 C++17 之前的任何 C++ 标准。
您可以设计自己的特征来查明 class 是否具有正确的 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;
};