C ++ 17使用std :: variant表示DOM [英] C++17 using std::variant to represent DOM

查看:115
本文介绍了C ++ 17使用std :: variant表示DOM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从C ++ 17学习如何使用std::variant.作为示例,开始使用它来表示DOM.尽管这项工作仍在进行中:

I'm trying to learn how to usestd::variant from C++17. As an example started using it, to represent the DOM. Though this is still work in progress:

  1. 我想就std::variant
  2. 的使用获得专家意见
  3. 还有一些有关编译器支持的输入.
  1. I wanted to get expert opinion on the usage of std::variant
  2. also some inputs on the compiler support.

我有DOM representation code( Godbolt的Compiler Explorer链接),它似乎可以很好地与 Clang trunk .但是,我看到同一代码无法使用 GCC 8.0.0 20171009 编译.

I've the DOM representation code (Godbolt's Compiler Explorer link) and it seems to compile fine with Clang trunk. However, I see that the same code does not compile with GCC 8.0.0 20171009.

我想了解这种不兼容的原因是什么.以及是否有人可以评论样式",以及这是否是std::variant的适当用法.

I would like to understand what is the reason for this incompatibility. And also if anyone can comment on the "style" and if this is an appropriate usage of std::variant.

#include <vector>
#include <type_traits>
#include <string>
#include <variant>
#include <unordered_map>

// https://dom.spec.whatwg.org/ : reference for the DOM.

namespace dragon {
    namespace dom {
        namespace traits_ns {
            template <bool valid_node_type = false>
            struct valid_node {
                static constexpr bool value = valid_node_type;
            };

            template <typename T>
            struct is_valid_node {
                static constexpr bool value = std::is_base_of<valid_node<true>, T>::value && T::value;
            };

            // TODO: Need to define policy concepts which will check if the children 
            // of each node is of the right, allowed type.
        }

        struct Element;
        struct Text;
        struct Document;
        struct Document_type;
        struct Document_fragment;
        struct Processing_instruction;
        struct Comment;

        using AttrList = std::vector<std::pair<std::string, std::string>>;
        using AttrSet = std::unordered_map<std::string, std::string>;
        using Node = std::variant<Document, Document_type, Document_fragment, Element, Text, Processing_instruction, Comment>;
        using Children = std::vector<Node>;


        struct Element final : traits_ns::valid_node<true> {
            Element(std::string t, const Children& c, const AttrList& a) : tag{ t }, child{ c } {}
            Element() = default;
            ~Element() = default;
            std::string tag;
            Children child;
            AttrSet attr;
        };

        struct Text final : traits_ns::valid_node<true> {
            explicit Text(std::string d) : data{ d } {}
            std::string data;
        };

        struct Document final : traits_ns::valid_node<true> {
            Document() = default;
            ~Document() = default;
        };

        struct Document_type final : traits_ns::valid_node<true> {};
        struct Document_fragment final : traits_ns::valid_node<true> {};
        struct Processing_instruction final : traits_ns::valid_node<true> {};
        struct Comment final : traits_ns::valid_node<true> {};

    } // namespace dom
} // namespace dragon


namespace dom = dragon::dom;
using std::vector;

int main()
{
    dom::Node t{dom::Text{"Hello"}};
    dom::Node e{dom::Element{"element", {}, {{"class", "blah"}}}};
    return 0;
}

GCC产生的错误摘要:

Snippet of errors Produced by GCC:

        #1 with x86-64 gcc (trunk)

    In file included from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/move.h:55:0,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/stl_pair.h:59,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/stl_algobase.h:64,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/vector:60,
                     from <source>:1:
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/type_traits: In instantiation of 'struct std::is_trivially_destructible<dragon::dom::Document>':
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/type_traits:2859:25:   required from 'constexpr const bool std::is_trivially_destructible_v<dragon::dom::Document>'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:309:5:   required from 'constexpr const bool std::__detail::__variant::_Traits<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>::_S_trivial_dtor'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:317:20:   required from 'constexpr const bool std::__detail::__variant::_Traits<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>::_S_trivial_move_assign'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:642:16:   required by substitution of 'template<class ... _Types> using _Move_assign_alias = std::__detail::__variant::_Move_assign_base<std::__detail::__variant::_Traits<_Types>::_S_trivial_move_assign, _Types ...> [with _Types = {dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment}]'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:645:12:   required from 'struct std::__detail::__variant::_Variant_base<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:1032:11:   required from 'class std::variant<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>'
    41 : <source>:41:86:   required from here
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/type_traits:1285:12: error: invalid use of incomplete type 'struct dragon::dom::Document'
         struct is_trivially_destructible
                ^~~~~~~~~~~~~~~~~~~~~~~~~
    28 : <source>:28:10: note: forward declaration of 'struct dragon::dom::Document'
       struct Document;
              ^~~~~~~~
    In file included from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/move.h:55:0,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/stl_pair.h:59,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/stl_algobase.h:64,
                     from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/vector:60,
                     from <source>:1:
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/type_traits: In instantiation of 'constexpr const bool std::is_trivially_destructible_v<dragon::dom::Document>':
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:309:5:   required from 'constexpr const bool std::__detail::__variant::_Traits<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>::_S_trivial_dtor'
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:317:20:   required from 'constexpr const bool std::__detail::__variant::_Traits<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>::_S_trivial_move_assign'

<SNIP> 

dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment}]' is implicitly deleted because the default definition would be ill-formed:
           variant(const variant& __rhs) = default;
           ^~~~~~~
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:1087:7: error: use of deleted function 'constexpr std::_Enable_copy_move<false, false, false, false, _Tag>::_Enable_copy_move(const std::_Enable_copy_move<false, false, false, false, _Tag>&) [with _Tag = std::variant<dragon::dom::Document, dragon::dom::Document_type, dragon::dom::Document_fragment, dragon::dom::Element, dragon::dom::Text, dragon::dom::Processing_instruction, dragon::dom::Comment>]'
    In file included from /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/variant:38:0,
                     from <source>:4:
    /opt/compiler-explorer/gcc-trunk-20171009/include/c++/8.0.0/bits/enable_special_members.h:301:15: note: declared here
         constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept  = delete;
                   ^~~~~~~~~~~~~~~~~
    Compiler exited with result code 1

        x86-64 gcc (trunk) (Editor #1, Compiler #1)

    g++ (GCC-Explorer-Build) 8.0.0 20171009 (experimental)- cached

推荐答案

元素的构造函数取决于Node类型,而Node类型取决于其他节点类型.

Element's constructor depends on the type Node, which depends on the other node types.

就构造函数的定义而言,这些其他节点类型不是完整的类型(它们在下面定义).

At the point of the definition of the constructor, these other node types are not complete types (they are defined below).

将构造函数的主体移到节点类型定义下方:

move the body of the constructor below the node type definitions:

#include <vector>
#include <type_traits>
#include <string>
#include <variant>
#include <unordered_map>

// https://dom.spec.whatwg.org/ : reference for the DOM.

namespace dragon {
    namespace dom {
        namespace traits_ns {
            template <bool valid_node_type = false>
            struct valid_node {
                static constexpr bool value = valid_node_type;
            };

            template <typename T>
            struct is_valid_node {
                static constexpr bool value = std::is_base_of<valid_node<true>, T>::value && T::value;
            };

            // TODO: Need to define policy concepts which will check if the children 
            // of each node is of the right, allowed type.
        }

        struct Element;
        struct Text;
        struct Document;
        struct Document_type;
        struct Document_fragment;
        struct Processing_instruction;
        struct Comment;

        using AttrList = std::vector<std::pair<std::string, std::string>>;
        using AttrSet = std::unordered_map<std::string, std::string>;
        using Node = std::variant<Document, Document_type, Document_fragment, Element, Text, Processing_instruction, Comment>;
        using Children = std::vector<Node>;


        struct Element final : traits_ns::valid_node<true> {
            Element(std::string t, const Children& c, const AttrList& a);
            Element() = default;
            ~Element() = default;
            std::string tag;
            Children child;
            AttrSet attr;
        };

        struct Text final : traits_ns::valid_node<true> {
            explicit Text(std::string d) : data{ d } {}
            std::string data;
        };

        struct Document final : traits_ns::valid_node<true> {
            Document() = default;
            ~Document() = default;
        };

        struct Document_type final : traits_ns::valid_node<true> {};
        struct Document_fragment final : traits_ns::valid_node<true> {};
        struct Processing_instruction final : traits_ns::valid_node<true> {};
        struct Comment final : traits_ns::valid_node<true> {};

        Element::Element(std::string t, const Children& c, const AttrList& a) : tag{ t }, child{ c } {}

    } // namespace dom
} // namespace dragon


namespace dom = dragon::dom;
using std::vector;

int main()
{
    dom::Node t{dom::Text{"Hello"}};
    dom::Node e{dom::Element{"element", {}, {{"class", "blah"}}}};
    return 0;
}

这篇关于C ++ 17使用std :: variant表示DOM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆