我想把一个对象放到一个std::map中,这个std::map的构造函数不接受任何参数。但是,std::map::emplace似乎除了键之外还需要至少一个额外的参数。那么我怎么才能把零个参数转发给构造函数呢?
std::map
std::map::emplace
rqenqsqc1#
std::map<K, V>的元素类型实际上是std::pair<K, V>,所以当你在map中嵌入时,参数会被转发到std::pair的构造函数。这就是为什么你不能只传递key:std::pair<K, V>不能由单个参数构造(除非它是另一对相同类型的参数)。您可以传递零个参数,但随后键将被值初始化,这可能不是您想要的。在大多数情况下,移动值的成本很低(键也很小,可以复制),你真的应该这样做:
std::map<K, V>
std::pair<K, V>
std::pair
M.emplace(k, V{});
其中V是Map类型。它将被初始化并移动到容器中。(移动甚至可能被省略;我不确定。)如果你不能移动,你真的需要V被就地构造,你必须使用分段构造构造器。
V
M.emplace(std::piecewise_construct, std::make_tuple(k), std::make_tuple());
这导致std::pair使用k构造第一个元素,使用零参数构造第二个元素(值初始化)。
k
8yparm6h2#
您可以显式创建一个pair并将其传递给map::emplace,或者使用std::pair的piecewise construction constructor。
pair
map::emplace
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());
Live demo
qco9c6ql3#
当我创建一个std::mutex对象的std::map时也遇到了同样的问题,问题是std::mutex既不能复制也不能移动,所以我需要“就地”构造它。接受的答案不适用于这种情况(M.emplace(k, V{});需要V是可移动的)。而且我不想使用复杂且可读性较差的std::piecewise_construct选项(请参阅上面的其他答案)。我的解决方案要简单得多-只需使用operator[]-它将使用其默认构造函数创建值并返回对它的引用。或者它只会查找并返回对现有项的引用,而不创建新项。
std::mutex
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 }
tvz2xvvm4#
在C++17中,你可以使用std::map::try_emplace,它在内部使用std::piecewise_construct,看起来并不那么麻烦。它还将一个键作为第一个参数(而不是像emplace那样将所有内容转发到std::pair::pair())。
std::map::try_emplace
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); }
Live example。
2nbm6dog5#
#include <iostream> #include <unordered_map> using namespace std; class A { public: A() { cout << "A ctor\n"; } A(int arg) { cout << "A ctor2\n"; } A(const char* arg) { cout << "A ctor3\n"; } A(int j, const char* arg) { cout << "A ctor4\n"; } A(const A& a) { cout << "A copy ctor\n"; } ~A() { cout << "A dtor\n"; } }; int main() { unordered_map<int, A> map; map.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, "ups")); }
打印输出
A ctor4 A dtor
iqxoj9l96#
Class ToolMap() { friend class std::map; public (std::map)Object ToolMap() { return Object; } }
6条答案
按热度按时间rqenqsqc1#
std::map<K, V>
的元素类型实际上是std::pair<K, V>
,所以当你在map中嵌入时,参数会被转发到std::pair
的构造函数。这就是为什么你不能只传递key:std::pair<K, V>
不能由单个参数构造(除非它是另一对相同类型的参数)。您可以传递零个参数,但随后键将被值初始化,这可能不是您想要的。在大多数情况下,移动值的成本很低(键也很小,可以复制),你真的应该这样做:
其中
V
是Map类型。它将被初始化并移动到容器中。(移动甚至可能被省略;我不确定。)如果你不能移动,你真的需要
V
被就地构造,你必须使用分段构造构造器。这导致
std::pair
使用k
构造第一个元素,使用零参数构造第二个元素(值初始化)。8yparm6h2#
您可以显式创建一个
pair
并将其传递给map::emplace
,或者使用std::pair
的piecewise construction constructor。Live demo
qco9c6ql3#
当我创建一个
std::mutex
对象的std::map
时也遇到了同样的问题,问题是std::mutex
既不能复制也不能移动,所以我需要“就地”构造它。接受的答案不适用于这种情况(
M.emplace(k, V{});
需要V是可移动的)。而且我不想使用复杂且可读性较差的std::piecewise_construct
选项(请参阅上面的其他答案)。我的解决方案要简单得多-只需使用
operator[]
-它将使用其默认构造函数创建值并返回对它的引用。或者它只会查找并返回对现有项的引用,而不创建新项。tvz2xvvm4#
在C++17中,你可以使用
std::map::try_emplace
,它在内部使用std::piecewise_construct
,看起来并不那么麻烦。它还将一个键作为第一个参数(而不是像emplace
那样将所有内容转发到std::pair::pair()
)。Live example。
2nbm6dog5#
打印输出
iqxoj9l96#