如何在值为 std::set 的 std::map 中使用 emplace() (从某物到集合的映射)?
How to use emplace() in a std::map whose value is a std::set (map from something to a set)?
问题
我有一个名为 misi
的 std::map<int, std::set<int>>
。我想知道为什么 misi.emplace(2345, {6, 9});
和 misi.emplace({2345, {6, 9}});
没有按预期工作,如下所示。
代码
#include <set> // std:set
#include <map> // std::map
#include <utility> // std::piecewise_construct, std::pair
#include <tuple> // std::forward_as_tuple
#include <iostream> // std::cout, std::endl
int main()
{
// --- std::set initializer list constructor ---
std::set<int> si({42, 16});
std::cout << "si.size(): " << si.size() << std::endl; // 2
std::cout << "*si.begin(): " << *si.begin() << std::endl; // 16
// --- std::set emplace() ---
si.emplace(7);
std::cout << "si.size(): " << si.size() << std::endl; // 3
std::cout << "*si.begin(): " << *si.begin() << std::endl; // 7
std::cout << "--------" << std::endl;
上面是std::set
,你可以看到初始化列表构造函数和emplace()
工作得很好。
// --- std::map initializer list constructor ---
std::map<int, int> mii({ {0, 42}, {1, 16} });
std::cout << "mii.size(): " << mii.size() << std::endl; // 2
std::cout << "mii[0]: " << mii[0] << std::endl; // 42
std::cout << "mii[1]: " << mii[1] << std::endl; // 16
// --- std::map emplace() ---
mii.emplace(1234, 7);
std::cout << "mii.size(): " << mii.size() << std::endl; // 3
std::cout << "mii[1234]: " << mii[1234] << std::endl; // 7
// --- std::map emplace() with std::pair() ---
mii.emplace(std::pair<int, int>(2345, 6));
std::cout << "mii.size(): " << mii.size() << std::endl; // 4
std::cout << "mii[2345]: " << mii[2345] << std::endl; // 6
std::cout << "--------" << std::endl;
上面是 int
到 int
的 std::map
,你可以看到这些方法也很完美,只是在最后一个例子中,std::pair
可能不知何故多余的。我想知道 std::pair
是否就地构建。 (好吧,我猜不是)
// --- std::map to std::set initializer list constructor ---
std::map<int, std::set<int>> misi({ {0, {42, 16}}, {1, {7}} });
std::cout << "misi.size(): " << misi.size() << std::endl; // 2
std::cout << "*misi[0].begin(): " << *misi[0].begin() << std::endl; // 16
std::cout << "*misi[1].begin(): " << *misi[1].begin() << std::endl; // 7
对于 std::map
到 std::set
,初始化列表构造函数如上所示完美运行。但是 emplace()
没有! (如下图)
// --- Compilation Errors ---
//misi.emplace(2345, 6, 9);
//misi.emplace({2345, 6, 9});
//misi.emplace(2345, {6, 9});
//misi.emplace({2345, {6, 9}});
//misi.emplace(
// std::piecewise_construct,
// std::forward_as_tuple(2345),
// std::forward_as_tuple(6, 9)
//);
//misi.emplace(
// std::piecewise_construct,
// std::forward_as_tuple(2345),
// std::forward_as_tuple({6, 9})
//);
在这里,下面的语法是可以的,但并不完全符合我的要求:
// --- OK ---
misi.emplace(std::pair<int, std::set<int>>(2345, {6, 9}));
std::cout << "misi.size(): " << misi.size() << std::endl; // 3
std::cout << "*misi[2345].begin(): " << *misi[2345].begin() << std::endl; //6
std::cout << "--------" << std::endl;
return 0;
}
所以,似乎没有办法就地创建 std::pair
,似乎 std::set
是就地创建的(对吧?)。有人有什么想法吗?
我使用的编译器是:
$ clang++ --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
大括号初始化器列表没有类型,因此无法完美转发。在这种特殊情况下,如果您希望就地构建所有内容,您可以明确指定类型 (std::initializer_list<int>
):
misi.emplace(
std::piecewise_construct,
std::forward_as_tuple(2345),
std::forward_as_tuple(std::initializer_list<int>{6, 9})
);
因为键和值只传递一个参数,而 std::set
的 initializer_list
构造函数不是 explicit
,您可以删除 piecewise_construct
完全并让 emplace
使用带有两个参数的构造函数构造 pair
:
misi.emplace(
2345,
std::initializer_list<int>{6, 9}
);
mii.emplace(std::pair<int, int>(2345, 6));
I wonder if the std::pair is constructed in-place or not. (Well, I
guess not)
不,构造了一个临时 std::pair<int, int>
并传递给 emplace
,它构造了 map
的 value_type
的一个实例(即 pair<const int, int>
) 用它。后者是实际存储在 map
.
中的内容
misi.emplace(std::pair<int, std::set<int>>(2345, {6, 9}));
it seems that the std::set is created in-place (right?).
没有。同样,这会创建一个临时 std::pair<int, std::set<int>>
,然后用它构造实际存储在 map
(即 pair<const int, std::set<int>>
)中的内容。第二个构造将从存储在临时文件中的 set<int>
执行移动。
问题
我有一个名为 misi
的 std::map<int, std::set<int>>
。我想知道为什么 misi.emplace(2345, {6, 9});
和 misi.emplace({2345, {6, 9}});
没有按预期工作,如下所示。
代码
#include <set> // std:set
#include <map> // std::map
#include <utility> // std::piecewise_construct, std::pair
#include <tuple> // std::forward_as_tuple
#include <iostream> // std::cout, std::endl
int main()
{
// --- std::set initializer list constructor ---
std::set<int> si({42, 16});
std::cout << "si.size(): " << si.size() << std::endl; // 2
std::cout << "*si.begin(): " << *si.begin() << std::endl; // 16
// --- std::set emplace() ---
si.emplace(7);
std::cout << "si.size(): " << si.size() << std::endl; // 3
std::cout << "*si.begin(): " << *si.begin() << std::endl; // 7
std::cout << "--------" << std::endl;
上面是std::set
,你可以看到初始化列表构造函数和emplace()
工作得很好。
// --- std::map initializer list constructor ---
std::map<int, int> mii({ {0, 42}, {1, 16} });
std::cout << "mii.size(): " << mii.size() << std::endl; // 2
std::cout << "mii[0]: " << mii[0] << std::endl; // 42
std::cout << "mii[1]: " << mii[1] << std::endl; // 16
// --- std::map emplace() ---
mii.emplace(1234, 7);
std::cout << "mii.size(): " << mii.size() << std::endl; // 3
std::cout << "mii[1234]: " << mii[1234] << std::endl; // 7
// --- std::map emplace() with std::pair() ---
mii.emplace(std::pair<int, int>(2345, 6));
std::cout << "mii.size(): " << mii.size() << std::endl; // 4
std::cout << "mii[2345]: " << mii[2345] << std::endl; // 6
std::cout << "--------" << std::endl;
上面是 int
到 int
的 std::map
,你可以看到这些方法也很完美,只是在最后一个例子中,std::pair
可能不知何故多余的。我想知道 std::pair
是否就地构建。 (好吧,我猜不是)
// --- std::map to std::set initializer list constructor ---
std::map<int, std::set<int>> misi({ {0, {42, 16}}, {1, {7}} });
std::cout << "misi.size(): " << misi.size() << std::endl; // 2
std::cout << "*misi[0].begin(): " << *misi[0].begin() << std::endl; // 16
std::cout << "*misi[1].begin(): " << *misi[1].begin() << std::endl; // 7
对于 std::map
到 std::set
,初始化列表构造函数如上所示完美运行。但是 emplace()
没有! (如下图)
// --- Compilation Errors ---
//misi.emplace(2345, 6, 9);
//misi.emplace({2345, 6, 9});
//misi.emplace(2345, {6, 9});
//misi.emplace({2345, {6, 9}});
//misi.emplace(
// std::piecewise_construct,
// std::forward_as_tuple(2345),
// std::forward_as_tuple(6, 9)
//);
//misi.emplace(
// std::piecewise_construct,
// std::forward_as_tuple(2345),
// std::forward_as_tuple({6, 9})
//);
在这里,下面的语法是可以的,但并不完全符合我的要求:
// --- OK ---
misi.emplace(std::pair<int, std::set<int>>(2345, {6, 9}));
std::cout << "misi.size(): " << misi.size() << std::endl; // 3
std::cout << "*misi[2345].begin(): " << *misi[2345].begin() << std::endl; //6
std::cout << "--------" << std::endl;
return 0;
}
所以,似乎没有办法就地创建 std::pair
,似乎 std::set
是就地创建的(对吧?)。有人有什么想法吗?
我使用的编译器是:
$ clang++ --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
大括号初始化器列表没有类型,因此无法完美转发。在这种特殊情况下,如果您希望就地构建所有内容,您可以明确指定类型 (std::initializer_list<int>
):
misi.emplace(
std::piecewise_construct,
std::forward_as_tuple(2345),
std::forward_as_tuple(std::initializer_list<int>{6, 9})
);
因为键和值只传递一个参数,而 std::set
的 initializer_list
构造函数不是 explicit
,您可以删除 piecewise_construct
完全并让 emplace
使用带有两个参数的构造函数构造 pair
:
misi.emplace(
2345,
std::initializer_list<int>{6, 9}
);
mii.emplace(std::pair<int, int>(2345, 6));
I wonder if the std::pair is constructed in-place or not. (Well, I guess not)
不,构造了一个临时 std::pair<int, int>
并传递给 emplace
,它构造了 map
的 value_type
的一个实例(即 pair<const int, int>
) 用它。后者是实际存储在 map
.
misi.emplace(std::pair<int, std::set<int>>(2345, {6, 9}));
it seems that the std::set is created in-place (right?).
没有。同样,这会创建一个临时 std::pair<int, std::set<int>>
,然后用它构造实际存储在 map
(即 pair<const int, std::set<int>>
)中的内容。第二个构造将从存储在临时文件中的 set<int>
执行移动。