模板构造函数解析基于方法或自由函数的存在

时间:2017-10-12 16:23:26

标签: c++ c++17 sfinae type-erasure

问题

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, ...)的模板构造函数通过检查SerializableT::serialize(...)

的存在来决定使用哪个模型

问题

是否可以通过任何方式(例如,SFINAE)自动构造serialize(const T&, ...),以便在可能的情况下使用方法序列化,否则使用自由函数序列化?

随意使用C ++ 17以外的任何C ++标准。

1 个答案:

答案 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
{};

[Live example]

然后,将新模板参数添加到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;
};