使用MFC对象初始化std::map不能编译通过。

3

我是一个MFC的初学者。

我尝试像这样初始化std :: map:(在CView的头文件中)

// myprogramView.h
std::map<int, CStatic> myMap = {{10,{}}, {11,{}}};

但是编译器报错:"no instance of constructor ... matches the argument list"。

(为了以后参考的编辑) 上面的消息是 IntelliSense 的错误。编译器(MSVC)说:C2664 'std::map<int,CStatic,std::less,std::allocator<std::pair<const _Kty,_Ty>>>::map(std::initializer_list<std::pair<const _Kty,_Ty>>)': 无法将参数1从'初始化列表'转换为'std::initializer_list<std::pair<const _Kty,_Ty>>'。

然而,我们可以进行以下类型的初始化:

std::map<int, std::string> myMap2 = { {10,{}}, {11,{}} };
std::map<int, std::map<std::string, int>> myMap3 = { {10,{}}, {11,{}} };

第一个示例为什么无法编译?如何使用包含MFC对象的map?
我尝试在运行时或在OnCreate中访问映射中的控件对象并调用.Create()方法。
我也尝试了CMap,但似乎出现了相同的问题。
j6t的答案解决了问题。只想澄清答案是关于std::initializer_list,而不是“成员初始化列表”。

4
请张贴完整的错误信息。 - molbdnilo
似乎不寻常地想要使用不会最终使用的值来初始化std::map。你真正想要解决的问题是什么? - IInspectable
@IInspectable 我只是想在一个for循环中为文本创建一些标签。所以我想创建一个包含CStatic的映射表会很方便,因为我可以通过键来访问它们(在for循环中键会不同)。也许我可以使用std::vector等,这只是一个快速的想法。 - starriet
1
你为什么不只存储控件ID和相应的文本条目的映射表呢?或者,如果所有这些在编译时已知,为什么不简单地使用包含ID和文本的结构体数组?CWnd::GetDlgItem将控件ID转换为控件。或者只需调用 CWnd::SetDlgItemText - IInspectable
@IInspectable 哦,谢谢你的建议。我应该认真考虑更好的工程方法(现在我只是试图快速实现,以后再重构)。无论如何,我的项目是一个SDI。你能给我一些提示,告诉我在SDI项目中应该使用什么来代替GetDlgItem或SetDlgItemText吗? - starriet
1
SDI项目中的窗口类派生自CWnd,因此您可以直接使用这些成员。 - IInspectable
1个回答

6

CObject 派生的 MFC 对象(如 CStatic)无法复制,因为它们有一个已删除的复制构造函数。但是,从初始化列表初始化需要可被复制构造的对象。


是的,GUI元素具有“身份”,不得复制。 - j6t
但是从CObject派生CArray的决定只是历史偶然,当时C++还处于萌芽阶段。如果那些设计师当时拥有并知道我们今天使用的工具和技术(包括序列化),他们会做出不同的决策。 - j6t
他们不会有。MFC中的每个可序列化对象都需要派生自CObject,因为它提供了所有低级支持(例如通过类名实例化对象)。与MFC的异常处理不同,序列化支持既不是历史意外,也不是在C++处于初期时的产物。 - IInspectable
@IInspectable 为什么 MFC 中的序列化需要被序列化的对象是不可复制的?实际上,正如您所知道的,包含可复制对象(例如 std::string)的 std::vectorstd::map 可以被序列化。 - starriet
1
@starriet 序列化支持需要从 CObject 派生。 CObject 有一个私有的复制构造函数,以防止意外的传值。显然,可以为任何数据类型设计序列化策略。但是,如果您想使用 MFC 的内置序列化,则必须从 CObject 派生并继承其不可复制的属性。 - IInspectable
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接