c++ - C++ 构造函数与相同键/值类型的 std::map 不明确
问题描述
这是一个类定义作为示例。
#include <string>
#include <map>
template <class T>
class Collection
{
private:
std::map<std::string, T> data;
public:
Collection() {}
Collection(std::map<std::string, T> d)
{
data = d;
}
};
int
这在使用s、char
s 甚至vector
模板类型初始化集合时效果很好。但是,当使用 a 初始化 astring
并调用第二个重载构造函数时,例如:
Collection<std::string> col({
{ "key", "value" }
});
它不编译,并抛出此退出错误:
main.cpp:24:22: error: call to constructor of 'Collection<std::__cxx11::string>'
(aka 'Collection<basic_string<char> >') is ambiguous
Collection<string> col({
^ ~
main.cpp:8:7: note: candidate constructor (the implicit move constructor)
class Collection
^
main.cpp:8:7: note: candidate constructor (the implicit copy constructor)
main.cpp:16:3: note: candidate constructor
Collection(map<string, T> d)
^
奇怪的是,虽然这种表示法适用于其他类型,但这会中断,但这种表示法适用于string
:
Collection<std::string> col(std::map<std::string, std::string>({
{ "key", "value" }
}));
这里发生了什么?
解决方案
这是一个有趣的。
Amap
可以由两个迭代器构造:
template<class InputIterator>
map(InputIterator first, InputIterator last,
const Compare& comp = Compare(), const Allocator& = Allocator());
值得注意的是,这个构造函数根本不需要检查它InputIterator
是一个迭代器,更不用说取消引用它的结果是否可以转换为map
的值类型。当然,实际上尝试构造映射会失败,但是要重载解析,map
可以从任何两个相同类型的参数构造。
所以随着
Collection<std::string> col({
{ "key", "value" }
});
编译器看到两种解释:
- 外大括号
map
使用map
的初始化列表构造函数初始化 a,内大括号pair
为该初始化列表构造函数初始化 a。 - 外大括号初始化 a
Collection
,内大括号map
使用“迭代器对”构造函数初始化 a 。
两者都是排名中的用户定义转换,两者之间没有决胜局,因此调用是模棱两可的 - 即使第二个,如果选择,会在map
构造函数内部的某个地方导致错误。
当您在最外层也使用大括号时:
Collection<std::string> col{{
{ "key", "value" }
}};
标准中有一条特殊规则排除了第二种解释。
推荐阅读
- google-apps-script - 从我的 gmail 帐户中搜索 bigquery 以获取 messageid
- cordova - 在您的 PATH 中找不到 native-run
- python - Pandas 仅将 Rank 应用于单个组
- php - FPDF 中的 FPDM 问题:FilterFlateDecode:无效的流数据
- css - “最小高度”属性未按预期工作
- r - 防止逗号在R中的表达式()中开始新行
- node.js - Mongodb 根据贡献度获取用户排名
- vaadin-flow - 如何更改 Vaadin 14 图表中的破折号样式?
- java - 解密时出现 AES BadPaddingException
- c# - 枚举器开销与字符串性能中的索引器