c++ - 分配自身的类型的分配器

标签 c++ templates allocator incomplete-type recursive-type

所以我得到了这个递归变体,它保存类型 std::vectorstd::unordered_map ,它们再次保存类型本身。

现在这应该符合标准,因为:

  1. std::unordered_map 基本上是一个仅保存引用的智能指针,在定义时它不需要知道类型的大小。
  2. 自引用std::vectorsN4510起被接受为标准正如另一个topic中提到的.

这是我所拥有的:

Demo

#include <variant>
#include <unordered_map>
#include <vector>
#include <string>
#include <memory> /* allocator */

template <typename StringType, typename Allocator>
class JSON;

template <typename StringType = std::string, typename Allocator = std::allocator</* map and vector */>>
class JSON : public std::variant<std::monostate,
                        std::unordered_map<StringType, JSON<StringType, Allocator>, std::hash<JSON<StringType, Allocator>>, std::equal_to<StringType>, Allocator>,
                        std::vector<JSON<StringType, Allocator>, Allocator>>
{ };

问题确实不是这个类对象的自相似性,而是它的分配器。如果分配器满足分配器完整性要求,它将起作用:

An incomplete type T may be used when instantiating vector if the allocator satisfies the allocator-completeness-requirements (17.6.3.5.1). T shall be complete before any member of the resulting specialization of vector is referenced.

但我无法实现这些,因为类型并非不完整,而是一个模板模板!

template <typename StringType = std::string,
    typename Allocator = std::allocator<JSON<StringType,
                            std::allocator<JSON<StringType,
                                std::allocator<JSON<StringType,
                                    ... >>>>>>>

意思是,我无法真正描述这种类型。在这种情况下我该怎么办?我可以使用自定义分配器来帮助自己吗?

简化:

这有效:

struct A {
    std::vector<A> subAs;
};

这不会:

template <typename Allocator>
struct A;

template <typename Allocator = std::allocator<A /* <-- unfortunately a template template parameter */>>
struct A {
    std::vector<A<Allocator>, Allocator> subAs;
};

但我想知道,由于分配器在第一个示例中是隐式的,因此将其显式化也应该可以工作吗?

最佳答案

std::unordered_map的分配器实际上并没有为 unordered_map::value_type 分配内存。元素,但用于内部节点结构。这是通过重新绑定(bind)分配器来完成的。

您可以通过接受任何分配器(此处 void 用作虚拟分配器)然后重新绑定(bind)它来执行类似的操作:

template <typename Allocator = std::allocator<void>>
struct A {
private:
    using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<super_vector<Allocator>>;
    using allocator = typename alloc_traits::allocator_type;
public:
    std::vector<A<Allocator>, allocator> vec_;
};

这样你就需要一个 A<std::allocator<void>> 的分配器,即std::allocator<A<std::allocator<void>>>没有“循环”。

应用于您的 JSON 结构:

template <typename StringType = std::string, typename Allocator = std::allocator<void>>
class JSON : public std::variant<std::monostate,
    std::unordered_map<StringType, JSON<StringType, Allocator>, std::hash<JSON<StringType, Allocator>>, std::equal_to<StringType>, typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const StringType, JSON<StringType, Allocator>>>>,
    std::vector<JSON<StringType, Allocator>, typename std::allocator_traits<Allocator>::template rebind_alloc<JSON<StringType, Allocator>>>>
{ };

但请注意 std::unordered_map当您实例化该类时,确实需要有一个完整的类型作为其映射类型。参见这里:How to have an unordered_map where the value type is the class it's in? 。你需要做一些其他的事情(我相信boost的unordered_map支持不完整类型,并且boost的recursive_variant做了一些事情以允许它用作常规unordered_map的映射类型)

关于c++ - 分配自身的类型的分配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76017190/

相关文章:

c++ - 从函数模板参数自动推断对容器的元素类型

c++ - 带有 std::vector 的自定义解除分配器不会被调用

c++ - 如何让一个类通过作用域分配器?

java - Velocity 模板引擎中列表的嵌套循环?

multithreading - 使用 OpenMP 时发生内存泄漏

c++ - 使用 MPI c 对整数求和 vector

python - 比较 Python、Numpy、Numba 和 C++ 的矩阵乘法

c++ - 输入信息的员工类C++。

c++ - g++ 和 Clang 关于数组大小

c++ - 未定义的模板成员引用