解决嵌套初始化列表数据结构的自引用问题



我试图解决这个难题:我正在使用一个变体val,它可能包含基本类型以及用户定义的容器,可以再次包含变体。如果没有盒子包装器对象,这种自引用数据结构是不可能实现的。这个包装器对象包装了容器arrayobj,并提供了一个可确定的内存布局,因为它只是持有指向这些容器的指针,而不是容器本身。

但是现在这里有一个问题:要使括号括起来的初始化列表语法与container一起工作,盒数据结构需要为keyvalval系列提供给定的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}} } };
|                                                                                                                     ^
|                                                                                                                     |
|   
  1. 您必须在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初始化),这意味着
  • 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>
    
    1. 感谢@user17732522关于不完整类型的评论。函数定义中的返回类型或参数类型必须是完整的,但声明中不需要。所以你需要把课堂定义外部毕竟类完成。

    演示

    相关内容

    • 没有找到相关文章

    最新更新