我试图解决这个难题:我正在使用一个变体val
,它可能包含基本类型以及用户定义的容器,可以再次包含变体。如果没有盒子包装器对象,这种自引用数据结构是不可能实现的。这个包装器对象包装了容器array
和obj
,并提供了一个可确定的内存布局,因为它只是持有指向这些容器的指针,而不是容器本身。
但是现在这里有一个问题:要使括号括起来的初始化列表语法与container
一起工作,盒数据结构需要为keyval
和val
系列提供给定的std::initializer_list-构造函数。然而,要定义val,我需要知道所涉及的所有模板参数的完整类型,包括box对象。但是这个同样需要知道val,这创建了一个互向定义集。我该如何解决这个问题?
Code (Compiler Explorer):
#include <string>
#include <variant>
#include <type_traits>
struct array;
struct obj;
struct keyval;
template <typename T>
struct box
{
box(std::initializer_list<keyval> init) {
}
box(std::initializer_list<val> init) {
}
T* ptr_;
};
using val = std::variant<std::monostate, box<array>, box<obj>, int, bool>;
struct obj
{
obj() {
}
obj(std::initializer_list<keyval> init) {
}
};
struct array
{
array() {
}
array(std::initializer_list<val> init) {
}
};
struct keyval
{
keyval() {
}
keyval(std::string str, val a) : key_{str}, val_{a} {
}
std::string key_;
val val_ = std::monostate{};
};
struct container : public array, public obj
{
using array::array;
using obj::obj;
};
int main()
{
container some_container = { {"first", true }, { "second", 1 }, { "third", {{"2first", 2}, {"2second", true}} } };
}
误差:
<source>:15:31: error: 'val' was not declared in this scope
15 | box(std::initializer_list<val> init) {
| ^~~
<source>:15:34: error: template argument 1 is invalid
15 | box(std::initializer_list<val> init) {
| ^
<source>: In function 'int main()':
<source>:59:117: error: could not convert '{{"first", true}, {"second", 1}, {"third", {{"2first", 2}, {"2second", true}}}}' from '<brace-enclosed initializer list>' to 'container'
59 | container some_container = { {"first", true }, { "second", 1 }, { "third", {{"2first", 2}, {"2second", true}} } };
| ^
| |
|
- 您必须在
struct box
的定义之前声明using
指令。由于val
的申报中提到了box
,所以必须提交box
的前向申报。
template <typename T>
struct box;
using val = std::variant<std::monostate, box<array>, box<obj>, int, bool>;
template <typename T>
struct box {};
std::variant
不能直接从std::initializer_list
初始化),这意味着- 感谢@user17732522关于不完整类型的评论。函数定义中的返回类型或参数类型必须是完整的,但声明中不需要。所以你需要把课堂定义外部毕竟类完成。
box<array> b{{"2first", 2},{"2second", true}}; // OK
val v1{b}; // OK
val v2{{"2first", 2},{"2second", true}}; // ERROR
这就是container
构建失败的原因。
container some_container = { {"first", true }, { "second", 1 }, { "third", box<array>{{"2first", 2}, {"2second", true}} } }; // note the box<array>