简单的问题:我如何让它发挥作用?
struct A {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
}
g ++错误:std :: pair&lt; _T1,_T2&gt; :: second的类型不完整
据我所知,在实例化地图时,编译器需要知道A的大小,但是它不知道这个,因为地图是在A的声明中声明的,所以这是解决这个问题的唯一方法。使用指针A(不想这样做)?
答案 0 :(得分:2)
除了使用不完整类型的智能指针之外,我不知道任何STL容器。如果您不想使用指针,则可以使用包装器结构:
struct A {
struct B { double whatever; };
std::unordered_map<std::string, B> mapToB;
};
编辑:如果以上内容不符合您的使用案例,则可以使用以下指针。
struct A {
double whatever;
std::unordered_map<std::string, std::unique_ptr<A>> mapToMoreA;
};
您也可以使用boost::unordered_map
,它不仅支持不完整的类型,而且在Visual Studio中具有更高的调试性能,因为Microsoft的std::unordered_map
实现由于过多的迭代器调试检查而非常低效。我不知道任何容器对gcc的任何性能问题。
答案 1 :(得分:2)
大多数情况下,它将取决于容器实现细节(更确切地说,取决于在容器声明点处实例化的内容以及什么不实例化)。显然,std::unordered_map
实现要求类型完整。与此同时,GCC的std::map
实现与不完整类型完全匹配。
为了说明这种差异的来源,请考虑以下示例。假设我们决定制作我们自己的std::vector
的天真实现 - 类似功能并声明我们的矢量类如下
template <typename T> class my_vector {
T *begin;
T *end;
...
};
只要我们的类定义只包含指向T
的指针,类型T
就不需要为类定义本身完成。我们可以为my_vector
实例化T
一个不完整的class X;
my_vector<X> v; // OK
而没有任何问题
my_vector
当我们开始使用(并因此实例化)T
的各个方法时,以后将需要该类型的“完整性”。
但是,如果出于某种原因我们决定在我们的向量类中包含template <typename T>
class my_vector {
T *begin;
T *end;
T dummy_element;
...
};
的直接实例,那么事情就会变得很糟糕
T
现在my_vector
的完整性将在class X;
my_vector<X> v; // ERROR, incomplete type
本身的实例化时很早就需要
unordered_map
在你的情况下必须发生类似的事情。您正在处理的A
的定义以某种方式包含unordered_map
的直接实例。这就是为什么不可能实例化的原因(显然,在这种情况下你最终会得到无限递归类型)。
通过A
的实施更好地考虑将确保不将A
作为直接成员包括在内。这样的实现不需要unordered_map
完成。正如您自己所指出的那样,Boost在{{1}}的实现在这方面设计得更好。
答案 2 :(得分:2)
Boost.Variant明确地为此目的提供了一个方便的实用程序 - boost::recusive_wrapper<>
。以下应该有效:
struct A {
double whatever;
std::unordered_map<std::string, boost::recursive_wrapper<A>> mapToMoreA;
};
唯一值得注意的缺点是Boost.Variant尚未更新以支持C ++ 11移动语义。更新:在Boost 1.56中添加。
答案 3 :(得分:0)
或使用指向地图的指针。在这种情况下,指针必须是void *类型(可以隐藏在一组函数后面)。也许std :: unordered_map可以替代不完整的值类型。
答案 4 :(得分:0)
在C ++中,对于不完整的类型,通常使用具有预定义常量大小的指针:
这当然会改变您使用地图的方式:您必须取消引用*
或->
运算符才能访问成员,并且必须在某些时候delete
指针。
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
};
A的成员函数应该拆分成struct
块内的原型并稍后实现,否则A及其成员尚未完全定义:
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
void doStuff(const std::string& str);
};
void A::doStuff(const std::string& str)
{
mapToMoreA[str] = new A();
}
答案 5 :(得分:0)
如果不接受地图保持指针,也许这对您有用:
struct A {
struct hidden;
std::unique_ptr<hidden> pimpl;
};
struct A::hidden {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
};
答案 6 :(得分:-2)
我认为您可以在定义之前转发声明struct A;
,编译器应该感到满意。
编辑:所以在被多次投票后,我写了下面的内容,看看我错过了什么:
#include <boost/unordered_map.hpp>
#include <string>
#include <iostream>
struct A;
struct A {
double whatever;
boost::unordered_map<std::string, A> mapToMoreA;
};
int main(void)
{
A b;
b.whatever = 2.5;
b.mapToMoreA["abc"] = b;
std::cerr << b.mapToMoreA["abc"].whatever << std::endl;
return 0;
}
这可以在我的mac上使用g ++ 4.2.1进行编译,并在运行时打印出“2.5”(如预期的那样)。
很抱歉,我没有unordered_map
没有提升。这是问题吗? (也就是说,std::unordered_map
是否会以某种方式对编译器施加比boost更多的约束?)否则,我不确定我在这里对这个问题缺少什么。那些贬低此事,请饶恕我的评论。谢谢!