我试图学习如何使用C ++ 17中的std::variant
。作为开始使用它的示例,表示DOM。虽然这仍在进行中:
std::variant
我是DOM representation code
(Godbolt's Compiler Explorer link),似乎可以使用Clang trunk
进行正常编译。但是,我发现相同的代码无法使用GCC 8.0.0 20171009
进行编译。
我想了解这种不兼容的原因是什么。而且,如果有人可以评论"风格"如果这是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制作的错误摘录:
#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
答案 0 :(得分:1)
元素的构造函数取决于Node的类型,它取决于其他节点类型。
在构造函数定义时,这些其他节点类型不是完整类型(它们在下面定义)。
将构造函数的主体移动到节点类型定义下面:
#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;
}