当前位置: 首页 > 知识库问答 >
问题:

带有boost变量的递归使用声明

孙震博
2023-03-14

我试图表示一个树状递归数据结构,其中每个节点可能是两种不同数据类型中的一种。我使用boost变体来“容纳”可能出现在每个节点上的两种类型。

但是,我遇到了一个问题。我严格使用“using”指令声明所有这些类型,因此当我到达节点的递归性质时,它会失败,因为typedef/using可能不会使用递归。

如何做到这一点?

using LeafData = int; // just for illustration
using LeafNode = std::unordered_map<std::string, LeafData>;
using InnerNode = std::unordered_map<std::string, boost_variant<InnerNode, LeafNode>>; // this is problematic since I'm using InnerNode recursively

我已经探索过使用boost::make_recursive_variant,但它创建的类型(A)并不完全是我所需要的,因为当我想要一个(B)由InnerNode或LeafNode组成的单个变量时,它会在一个变量中创建一个变量。

(A) boost_variant<boost_variant<InnerNode, LeafNode>, LeafNode>
(B) boost_variant<InnerNode, LeafNode>

共有3个答案

端木狐若
2023-03-14

我能够让boost::make_recursive_variant方法工作,但它需要一个变量访问者的附加处理程序。

using LeafData = int; // just for illustration
using LeafNode = std::unordered_map<std::string, LeafData>;
using InnerNode = std::unordered_map<std::string, boost::make_recursive_variant<boost::recursive_variant_, LeafNode>::type>;

变体访问者需要处理三种类型,LeafNode、InnerNode、AND、InnerNode::mapped_type(这是递归变体),然后编译器看起来很高兴。不过不确定这是否“有效”,所以需要运行并查看行为如何。

贾骏喆
2023-03-14

您将需要一个指针,变量要么是叶数据,要么是指向另一个叶的指针。

祁烈
2023-03-14

您可以使用< code > make _ recursive _ variant 做您想做的事情:

在Coliru上直播

#include <boost/variant.hpp>
#include <unordered_map>

struct LeafData {
    int _i;
    LeafData(int i) : _i(i) {}
}; // just for illustration

using LeafNode = std::unordered_map<std::string, LeafData>;

using Node = boost::make_recursive_variant<
        LeafNode,
        std::unordered_map<std::string, boost::recursive_variant_>
    >::type;

using Inner = std::unordered_map<std::string, Node>;

int main() {
    Node tree = Inner {
        { "a", LeafNode { { "one", 1 }, { "two", 2 }, { "three",3 } } },
        { "b", Inner {
                { "b1", LeafNode { { "four", 4 }, { "five", 5 }, { "six", 6 } } },
                { "b2", LeafNode { { "seven", 7 }, { "eight", 8 }, { "nine", 9 } } },
            }
        },
        { "c", LeafNode {} },
    };
}

为什么要区分内部/叶节点?在我看来,叶节点只是具有值而不是子级的节点:

在Coliru上直播

#include <boost/variant.hpp>
#include <unordered_map>

struct Data {
    int _i;
    Data(int i) : _i(i) {}
}; // just for illustration

using Tree = boost::make_recursive_variant<
        Data,
        std::unordered_map<std::string, boost::recursive_variant_>
    >::type;

using Node = std::unordered_map<std::string, Tree>;

int main() {
    Tree tree = Node {
        { "a", Node { { "one", 1 }, { "two", 2 }, { "three",3 } } },
        { "b", Node {
                { "b1", Node { { "four", 4 }, { "five", 5 }, { "six", 6 } } },
                { "b2", Node { { "seven", 7 }, { "eight", 8 }, { "nine", 9 } } },
            }
        },
        { "c", Node {} },
    };
}

你可以很有远见地宣布:

在Coliru上直播

#include <boost/variant.hpp>
#include <unordered_map>

struct Data {
    int _i;
    Data(int i) : _i(i) {}
}; // just for illustration

struct Node;

using Tree = boost::variant<Data, boost::recursive_wrapper<Node> >;

struct Node : std::unordered_map<std::string, Tree> {
    using base = std::unordered_map<std::string, Tree>;
    using base::base; // inherit constructor
};

int main() {
    Tree tree = Node {
        { "a", Node { { "one", 1 }, { "two", 2 }, { "three",3 } } },
        { "b", Node {
                { "b1", Node { { "four", 4 }, { "five", 5 }, { "six", 6 } } },
                { "b2", Node { { "seven", 7 }, { "eight", 8 }, { "nine", 9 } } },
            }
        },
        { "c", Node {} },
    };
}

如果您使用的<code>unordered_map

在这个过程中,我们可以使构造器更加智能,树的构造更加简洁:

在Coliru上直播

#include <boost/variant.hpp>
#include <boost/unordered_map.hpp>

struct Data {
    int _i;
    Data(int i = 0) : _i(i) {}
}; // just for illustration

struct Node : boost::variant<Data, boost::unordered_map<std::string, Node> > {
    using Map = boost::unordered_map<std::string, Node>;
    using Base = boost::variant<Data, Map>;

    using Base::variant;
    using Base::operator=;

    Node(std::initializer_list<Map::value_type> init) : Base(Map(init)) {}
};

int main() {
    auto tree = Node {
        { "a", { { "one", 1 }, { "two", 2 }, { "three", 3 } } },
        { "b", {
                { "b1", { { "four", 4 }, { "five", 5 }, { "six", 6 } } },
                { "b2", { { "seven", 7 }, { "eight", 8 }, { "nine", 9 } } },
            }
        },
        { "c", {} },
    };
}

(我认为C17将其添加到标准库规范中)

 类似资料:
  • 我写了下面的代码来反转链表的前K个节点,它在反转链表的前K个节点时解决了一些问题,为什么递归在最后一次迭代中执行两次,现在它可以正常工作,但为什么它会导致链表中的循环当我尝试在“if”条件下使用变量“k”而不是“PresCouner”时,原因是什么?以及如何避免它?

  • 对于二进制搜索树,我只能访问根节点,而我正在尝试编写一个递归方法来挖掘其左节点。 例如 root.left(); 成为 根左()。左(); 然后, 根左()。左(); 你看这是怎么回事...有没有递归的方法来更改/添加到变量中?

  • 函数甚至可以不使用局部变量来调用自己. 例子 23-14. 汉诺塔 1 #! /bin/bash 2 # 3 # 汉诺塔(The Towers Of Hanoi) 4 # Bash script 5 # Copyright (C) 2000 Amit Singh. All Rights Reserved. 6 # http://hanoi.kernelthrea

  • 我正在做一个简单的天气应用程序,我有一个问题,通过AsyncTask读取变量。我是andorid编程的初学者,所以我要求理解。因此,我想将变量“latitude”和“longitude”从place picker中选择到asynctask.execute(“latitude”,“longitude”)中,并刷新屏幕以显示新位置的天气。但我注意到,当我在代码中不是通过变量(例如asynctask.e

  • 我正在尝试向我的网站添加一个喜欢的功能。我使用以下模式制作了一个喜欢的集合。我正在使用自定义_id来避免创建额外的索引。 我的服务器上有一个路由,它使用MongoDB聚合搜索帖子集合。我正在尝试向当前管道中添加一个$lookup阶段,以便添加一个liked属性,该属性的类型为布尔值,表示用户是否喜欢该帖子。下面是无法工作的$查找阶段(liked始终返回空数组,即使有相应的liked文档): 我认为

  • 即使不适用局部变量,函数也可以递归的调用自身。 例子24-16. 斐波那契序列 #!/bin/bash # fibo.sh : 斐波那契序列 (递归) # 作者: M. Cooper # License: GPL3 # ----------算法-------------- # Fibo(0) = 0 # Fibo(1) = 1 # else # Fibo(j) = Fibo(j-1) + Fi