使用模板检查结构中的字段,如果失败则启用函数,如果失败则给出漂亮的错误消息? 我有一个C++类,它定义了一个数据序列化接口到JSON: class JsonSerializable { public: QJsonDocument toJSON() const; void fromJSON(QJsonDocument const& json); protected: virtual QJsonDocument serialize() const = 0; virtual oid deserialize(QJsonDocument const& json) = 0; };

使用模板检查结构中的字段,如果失败则启用函数,如果失败则给出漂亮的错误消息? 我有一个C++类,它定义了一个数据序列化接口到JSON: class JsonSerializable { public: QJsonDocument toJSON() const; void fromJSON(QJsonDocument const& json); protected: virtual QJsonDocument serialize() const = 0; virtual oid deserialize(QJsonDocument const& json) = 0; };,c++,templates,metaprogramming,C++,Templates,Metaprogramming,toJSON()与serialize()及其对应方法的思想是,类需要实现的受保护方法只需要关心实际处理数据,而公共方法执行基本的有效性检查 现在我想介绍用于更细粒度检查的JSON模式。我只想在存在模式的情况下启用JSON模式部分。因此,我开始引入一个struct,如下所示: template <class Serializable> struct JsonSchema {}; template <> struct JsonSchema<MySerializ

toJSON()
serialize()
及其对应方法的思想是,类需要实现的受保护方法只需要关心实际处理数据,而公共方法执行基本的有效性检查

现在我想介绍用于更细粒度检查的JSON模式。我只想在存在模式的情况下启用JSON模式部分。因此,我开始引入一个
struct
,如下所示:

 template <class Serializable>
 struct JsonSchema {};

 template <>
 struct JsonSchema<MySerializingClass>
 {
      static const char schemaURI[] = "...";
 };
模板
结构JsonSchema{};
模板
结构JsonSchema
{
静态常量char schemaURI[]=“…”;
};
我尚未完成该方法,因为我不确定如何实现以下目标:

  • 只有当存在
    JsonSchema
    结构的模板专门化时,才应编译
    fromJSON()
    中的模式检查代码
  • 如果这个结构存在,我希望编译器检查
    schemaURI
    字段是否存在,以及它的大小是否大于0。如果没有,我想给程序员一个描述性的错误消息,就像我可以使用
    BOOST\u STATIC\u ASSERT
    一样

  • 可能吗?API尚未最终确定;这里最重要的部分是检查应该在编译时进行。
    schemaURI
    参数由程序员设置,在运行时不会更改---模式文件是分布式程序的一部分,通过资源系统进行管理,因此如果程序编译,它保证可用。

    我相信您当前的设计不可能满足您的要求。例如,您的
    fromJSON
    示例代码不可能静态地知道调用它的类的类型。由于您需要编译类型检查,我认为您可能必须使用静态多态性,如下所示:

    template<typename T>
    struct JsonSchema {};
    
    template<typename Derived, typename SchemaCheck = void>
    class JsonSerializable {
    public:
        QJsonDocument toJSON() const;
        void fromJSON(QJsonDocument const& json);
    };
    
    template<typename Derived, typename SchemaCheck>
    QJsonDocument JsonSerializable<Derived,SchemaCheck>::toJSON() const {
        // do whatever you need to do here, and call serialize() like this:
        static_cast<Derived const*>(this)->serialize();
    }
    
    template<typename Derived, typename SchemaCheck>
    void JsonSerializable<Derived,SchemaCheck>::fromJSON(QJsonDocument const& json) {
        // do whatever you need to do when there's no schema, and call deserialize() like this:
        static_cast<Derived*>(this)->deserialize(json);
    }
    
    template<typename Derived>
    class JsonSerializable<Derived,
        // We check extent > 1 instead of extent > 0 because a string constant of length 0 requires an array of length 1 to hold it.
        // If schemaURI doesn't exist at all, this will also fail and cause the default version (above) to be used.
        std::enable_if<(std::extent<decltype(JsonSchema<Derived>::schemaURI)>::value > 1), Derived>> {
    public:
        // It's probably easier to define these inline. It might get pretty complicated otherwise.
        QJsonDocument toJSON() const {
            // Pretty much the same as before, unless you need some different behaviour when there's a schema
            static_cast<Derived const*>(this)->serialize();
        }
        void fromJSON(QJsonDocument const& json) {
            // There's a schema now, so act accordingly.
            static_cast<Derived*>(this)->deserialize(json);
        }
    };
    
    class MySerializingClass : public JsonSerializable<MySerializingClass> {
    public:
        QJsonDocument serialize() const;
        void deserialize(QJsonDocument const& json);
    };
    
    template<typename Derived>
    class JsonSerializable<Derived,
        // We check extent > 1 instead of extent > 0 because a string constant of length 0 requires an array of length 1 to hold it.
        std::enable_if<(std::extent<decltype(JsonSchema<Derived>::schemaURI)>::value > 1), Derived>> : public JsonSerializableBase
    
    然后将
    JsonSerializable
    声明更改为从中继承:

    template<typename Derived, typename SchemaCheck = void>
    class JsonSerializable : public JsonSerializableBase
    

    希望它能满足您的需要。

    如果有人想知道,如果静态多态性不是一个选项,例如,当Qt的moc干扰时,如何实现这一点:那么,一个自由函数可以帮助您。代码如下:

    class JsonSerializable
    {
    public:
        virtual QJsonDocument toJSON() const = 0;
        virtual void fromJSON(const QJsonDocument &json) = 0;
    };
    
    
    template <class C>
    struct JsonSchema
    {
        static constexpr char const schemaURI[] = "";
    };
    
    
    template <
        class C,
        typename std::enable_if<(std::is_base_of<JsonSerializable, C>
                ::value
            && std::extent<decltype(JsonSchema<C>::schemaURI)>
                 ::value <= 1),
            int>::type = 0>
    void deserialize(C& serializable, QJsonDocument const& json)
    {
        serializable.fromJSON(json);
    }
    
    
    template <
        class C,
        typename std::enable_if<(std::is_base_of<JsonSerializable, C>
                ::value
            && std::extent<decltype(JsonSchema<C>::schemaURI)>
                 ::value > 1),
            int>::type = 0>
    void deserialize(C& serializable, QJsonDocument const& json)
    {
        /* Do the schema checking here: */
    
        checkSchema(json, JsonSerializable<C>::schemaURI);
        serializable.fromJSON(json);
    }
    
    类JsonSerializable { 公众: 虚拟QJsonDocument toJSON()常量=0; 来自json的虚拟void(const QJsonDocument&json)=0; }; 模板 结构JsonSchema { 静态constexpr char const schemaURI[]=“”; }; 模板< 丙级,, typename std::启用\u如果 void反序列化(C&serializable,qjsondocumentconst&json) { serializable.fromJSON(json); } 模板< 丙级,, typename std::启用_(如果为1), int>::type=0> void反序列化(C&serializable,qjsondocumentconst&json) { /*在此处执行架构检查:*/ checkSchema(json,JsonSerializable::schemaURI); serializable.fromJSON(json); }
    其中一部分可能不可能(检查大小是否大于0)。如果您需要
    const-char[]
    而不是
    const-char*
    const-char[]
    可能会更合理,请原谅这个错误。一切都应该在编译时发生,所以
    static const char[]
    可能更好。。。我会调整我的问题。谢谢我不认为这是一个错误-
    constchar*
    毕竟是分配字符串文字时使用的正常方法,而且它没有错。使用
    const char[]
    意味着编译器应该知道它的长度-我相信在
    中可能有一些东西可以获得数组类型的长度。顺便说一下,您可以这样声明:
    static const char schemaURI[]=“…”谢谢!长度检查是一个很好的选择,我打赌如果其余的工作正常,我会得到。。。关于模板魔术有什么想法吗?是的,这确实告诉了我怎么做。因为我的API还没有完成,所以我可以很容易地实现它。非常感谢!
    
    using QJsonDocument = std::string; // Since I don't have Qt handy
    int main(int,char*[]) {
        MySerializingClass foo;
        foo.toJSON();
        foo.fromJSON("abc");
        return 0;
    }
    
    class JsonSerializable
    {
    public:
        virtual QJsonDocument toJSON() const = 0;
        virtual void fromJSON(const QJsonDocument &json) = 0;
    };
    
    
    template <class C>
    struct JsonSchema
    {
        static constexpr char const schemaURI[] = "";
    };
    
    
    template <
        class C,
        typename std::enable_if<(std::is_base_of<JsonSerializable, C>
                ::value
            && std::extent<decltype(JsonSchema<C>::schemaURI)>
                 ::value <= 1),
            int>::type = 0>
    void deserialize(C& serializable, QJsonDocument const& json)
    {
        serializable.fromJSON(json);
    }
    
    
    template <
        class C,
        typename std::enable_if<(std::is_base_of<JsonSerializable, C>
                ::value
            && std::extent<decltype(JsonSchema<C>::schemaURI)>
                 ::value > 1),
            int>::type = 0>
    void deserialize(C& serializable, QJsonDocument const& json)
    {
        /* Do the schema checking here: */
    
        checkSchema(json, JsonSerializable<C>::schemaURI);
        serializable.fromJSON(json);
    }