为什么 std::map::operator[] 赋值需要一个无参数的构造函数?
Why does std::map::operator[] assignment require an argumentless constructor?
我有以下最小示例在我的代码中重现错误:
#include <unordered_map>
#include <iostream>
class B
{
public:
B(int b) : m_b{ b } {}
int m_b;
};
int main()
{
using std::cout, std::endl;
std::unordered_map<int, B> ab{};
ab[1] = B(3);
//ab.insert(std::pair<int, B>(1, B(3)));
cout << ab[1].m_b << endl;
}
这失败了,并出现了一个冗长而笨拙的错误,这基本上相当于说 B
没有不带任何参数的构造函数。错误源于 ab[1] = B(3)
为什么需要这样做?为什么使用 insert
而不是 operator[]
不需要那个构造函数?
加分为什么在我的原始代码中有这一行:
Vec2 pos{ m_orbits[&p].positionAtTime(m_time + dt) };
还需要一个非参数化的构造函数。我无法在我的最小示例中重现该错误,但是 m_orbits
是一个无序映射,其中指向 Particle
对象的指针作为键,指向 Orbit
对象的指针作为值。 positionAtTime
是Orbit
的一个const
成员函数,计算某时刻粒子在轨道上的位置。
Why is [a constructor for B
without any arguments] needed?
这是因为 std::map::operator[]
要求 mapped_type
(即在您的情况下 B
)是默认可构造的。
- Inserts
value_type(key, T())
if the key does not exist. This function is equivalent to return insert(std::make_pair(key, T())).first->second
;
key_type
must meet the requirements of CopyConstructible.
mapped_type
must meet the requirements of CopyConstructible and DefaultConstructible.
If an insertion is performed, the mapped value is value-initialized (default-constructed for class types, zero-initialized otherwise) and a reference to it is returned.
当您提供用户定义的构造函数(即 B(int b)
)时,compiler will not generate a default constructor automatically,因此 A
不能默认可解释。
If some user-declared constructors are present, the user may still force the automatic generation of a default constructor by the compiler that would be implicitly-declared otherwise with the keyword default.
因此,出现上述错误!
why does using insert
instead of operator[]
not need that constructor?
因为 std::map::insert
依赖于 value_type
(即 std::pair<const Key, T>
)。对于您的 ab
,这是 std::pair<const int, B>
。从 cppreference.com 函数重载:
1-3) Inserts value. The overload (2) is equivalent to emplace(std::forward<P>(value))
and only participates in overload resolution if std::is_constructible<value_type, P&&>::value == true
.
4-6) Inserts value in the position as close as possible, just prior(since C++11), to hint. The overload (5) is equivalent to emplace_hint(hint, std::forward<P>(value))
and only participates in overload resolution if std::is_constructible<value_type, P&&>::value == true
.
所以只要 B
可以构建,std::pair<const int, B>
也可以构建,std::map::insert
可以工作。
我有以下最小示例在我的代码中重现错误:
#include <unordered_map>
#include <iostream>
class B
{
public:
B(int b) : m_b{ b } {}
int m_b;
};
int main()
{
using std::cout, std::endl;
std::unordered_map<int, B> ab{};
ab[1] = B(3);
//ab.insert(std::pair<int, B>(1, B(3)));
cout << ab[1].m_b << endl;
}
这失败了,并出现了一个冗长而笨拙的错误,这基本上相当于说 B
没有不带任何参数的构造函数。错误源于 ab[1] = B(3)
为什么需要这样做?为什么使用 insert
而不是 operator[]
不需要那个构造函数?
加分为什么在我的原始代码中有这一行:
Vec2 pos{ m_orbits[&p].positionAtTime(m_time + dt) };
还需要一个非参数化的构造函数。我无法在我的最小示例中重现该错误,但是 m_orbits
是一个无序映射,其中指向 Particle
对象的指针作为键,指向 Orbit
对象的指针作为值。 positionAtTime
是Orbit
的一个const
成员函数,计算某时刻粒子在轨道上的位置。
Why is [a constructor for
B
without any arguments] needed?
这是因为 std::map::operator[]
要求 mapped_type
(即在您的情况下 B
)是默认可构造的。
- Inserts
value_type(key, T())
if the key does not exist. This function is equivalent to returninsert(std::make_pair(key, T())).first->second
;
key_type
must meet the requirements of CopyConstructible.mapped_type
must meet the requirements of CopyConstructible and DefaultConstructible. If an insertion is performed, the mapped value is value-initialized (default-constructed for class types, zero-initialized otherwise) and a reference to it is returned.
当您提供用户定义的构造函数(即 B(int b)
)时,compiler will not generate a default constructor automatically,因此 A
不能默认可解释。
If some user-declared constructors are present, the user may still force the automatic generation of a default constructor by the compiler that would be implicitly-declared otherwise with the keyword default.
因此,出现上述错误!
why does using
insert
instead ofoperator[]
not need that constructor?
因为 std::map::insert
依赖于 value_type
(即 std::pair<const Key, T>
)。对于您的 ab
,这是 std::pair<const int, B>
。从 cppreference.com 函数重载:
1-3) Inserts value. The overload (2) is equivalent to
emplace(std::forward<P>(value))
and only participates in overload resolution ifstd::is_constructible<value_type, P&&>::value == true
.4-6) Inserts value in the position as close as possible, just prior(since C++11), to hint. The overload (5) is equivalent to
emplace_hint(hint, std::forward<P>(value))
and only participates in overload resolution ifstd::is_constructible<value_type, P&&>::value == true
.
所以只要 B
可以构建,std::pair<const int, B>
也可以构建,std::map::insert
可以工作。