所以我得到了这个递归变体,它保存类型 std::vector
和 std::unordered_map
,它们再次保存类型本身。
现在这应该符合标准,因为:
这是我所拥有的:
#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/