我正在审查我的一些旧代码,我看到代码使用指针来实现Variant
个对象的树。它是一棵树,因为每个Variant
都可以包含unordered_map
Variant*
。
我查看了代码,并想知道为什么不只是使用值std::vector<Variant>
和std::unordered_map<std::string, Variant>
,而不是Variant*
。
所以我继续改变它。好像除了一件事,我得到了errors:
/usr/local/include/c++/6.1.0/bits/stl_pair.h:153:11: error: 'std::pair<_T1, _T2>::second' has incomplete type _T2 second; /// @c second is a copy of the second object ^~~~~~ main.cpp:11:8: note: forward declaration of 'struct Variant' struct Variant ^~~~~~~
所以我认为我可以欺骗编译器延迟知道该类型的需要,didn't work either。
我认为这比较早,但实际上并没有,我忘记了::type
using HideMap...
#include <vector>
#include <unordered_map>
#include <iostream>
template<typename K, typename V>
struct HideMap
{
using type = std::unordered_map<K, V>;
};
struct Variant
{
using array_container = std::vector<Variant>;
// Does not work either
using object_container = typename HideMap<std::string, Variant>::type;
// Fails
//using object_container = std::unordered_map<std::string, Variant>;
private:
union Union
{
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
Union data;
bool weak;
};
int main()
{
Variant v;
std::cout << "Works" << std::endl;
}
所以,我的问题是,为什么它适用于vector
而不是unordered_map
?
如果问题是无法使用不完整类型,是否有办法延迟unordered_map
的实例化?我真的不希望每个对象属性都是单独的new
分配。
答案 0 :(得分:1)
这使用placement new来将Union
的初始化推迟到Variant
是完整类型的构造函数。您需要reinterpret_cast
所需的任何地方Union
。我努力不违反任何严格的行为。
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
struct Variant {
Variant();
~Variant();
private:
std::aligned_union<0, std::vector<Variant>,
std::unordered_map<std::string, void *>,
std::int64_t>::type data;
};
namespace Variant_detail {
using array_container = std::vector<Variant>;
using object_container = std::unordered_map<std::string, Variant>;
union Union {
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
}
Variant::Variant() {
//make sure that std::unordered_map<std::string, Variant> is not too large
static_assert(sizeof(std::unordered_map<std::string, Variant>) <=
sizeof data, "Variant map too big");
static_assert(alignof(std::unordered_map<std::string, Variant>) <=
alignof(decltype(data)), "Variant map has too high alignment");
auto &my_union = *new (&data) Variant_detail::Union;
my_union.vint = 42;
}
Variant::~Variant() {
reinterpret_cast<Variant_detail::Union &>(data).~Union();
}
int main() {
Variant v;
std::cout << "Works" << std::endl;
}