【发布时间】:2014-12-18 18:59:28
【问题描述】:
我想将一个对象放置到 std::map 中,其构造函数不接受任何参数。但是,std::map::emplace 似乎除了键之外至少需要一个额外的参数。那么如何将零参数转发给构造函数呢?
【问题讨论】:
我想将一个对象放置到 std::map 中,其构造函数不接受任何参数。但是,std::map::emplace 似乎除了键之外至少需要一个额外的参数。那么如何将零参数转发给构造函数呢?
【问题讨论】:
std::map<K, V> 的元素类型实际上是std::pair<K, V>,所以当你放入地图时,参数将被转发给std::pair 的构造函数。这就是为什么你不能只传递键:std::pair<K, V> 不能从单个参数构造(除非它是另一对相同类型。)你可以传递零个参数,但是键将被初始化,这可能不是你想要的。
在大多数情况下,移动值会很便宜(并且键会很小且可复制),您真的应该这样做:
M.emplace(k, V{});
其中V 是映射类型。它将被值初始化并移动到容器中。 (这个动作甚至可能被忽略;我不确定。)
如果你不能移动,而你确实需要就地构造V,你必须使用分段构造构造函数...
M.emplace(std::piecewise_construct, std::make_tuple(k), std::make_tuple());
这会导致std::pair 使用k 构造第一个元素,使用零参数(值初始化)构造第二个元素。
【讨论】:
forward_as_tuple 而不是make_tuple?
forward_as_tuple。
M[k]; 与piecewise_construct 的效果相同。
make_tuple 适用于不可移动的类型。 forward_as-tuple 也会尝试移动,这对我的班级来说是不可能的(故意的)。 @Brian 在这里救了我。
您可以显式创建pair 并将其传递给map::emplace,或者使用std::pair 的piecewise construction constructor。
struct foo {};
std::map<int, foo> m;
m.emplace(std::pair<int, foo>(1, {}));
m.emplace(std::piecewise_construct,
std::forward_as_tuple(2),
std::forward_as_tuple());
【讨论】:
当我必须创建 std::map 的 std::mutex 对象时,我遇到了同样的问题。问题是std::mutex 既不能复制也不能移动,所以我需要“就地”构建它。
接受的答案不适用于这种情况(M.emplace(k, V{}); 需要 V 是可移动的)。而且我不想使用复杂且可读性较差的std::piecewise_construct 选项(请参阅上面的其他答案)。
我的解决方案要简单得多——只需使用operator[]——它将使用其默认构造函数创建值并返回对它的引用。或者它只会查找并返回对现有项目的引用而不创建新项目。
std::map<std::string, std::mutex> map;
std::mutex& GetMutexForFile(const std::string& filename)
{
return map[filename]; // constructs it inside the map if doesn't exist
}
【讨论】:
try_emplace(仅限 C++17)或 emplace,详见其他答案。另请注意,此答案在视觉上更清晰,但速度稍慢(仅在您大量执行此操作时才真正重要),因为它(即operator[])必须检查对象是否存在,因此它可以知道是否返回它找到的东西或先在那里创建一个新对象。
在 C++17 中,您可以使用 std::map::try_emplace,它在内部使用 std::piecewise_construct,并且看起来不那么麻烦。它还接受一个键作为第一个参数(而不是像emplace 那样将所有内容都转发到std::pair::pair())。
#include <map>
struct A {
A() = default;
};
int main()
{
std::map<int, A> map;
map.emplace(std::piecewise_construct,
std::forward_as_tuple(10),
std::forward_as_tuple());
// ...vs...
map.try_emplace(10);
}
【讨论】:
try_emplace() 几乎就是 emplace() 应该的样子。
Class ToolMap()
{
friend class std::map;
public (std::map)Object ToolMap()
{
return Object;
}
}
【讨论】: