C++11標準ライブラリのコンテナには、emplace()
、emplace_back()
といったメンバ関数が追加されました。これらの関数は、コンテナの要素型のコンストラクタ引数を受け取り、要素型のオブジェクトをemplace()
/emplace_back()
の内部で一度だけ作る、という効率化の役割を果たしてくれます。
std::vector
のemplace_back()
なら、以下のように、要素型X
のコンストラクタ引数を渡すという、シンプルな使い方ができます。
struct X { X(int a, int b, int c) {} }; std::vector<X> v; v.emplace_back(1, 2, 3);
しかし、std::map
のemplace()
は、使うのがちょっと難しいです。map
はキーと値の組を扱うので、要素を追加する際、それぞれのコンストラクタ引数を受け取ろうとすると、引数の区切りがどこなのかがわからないのです。
std::map<X, Y> m; // どこまでがXの引数で、どこからがYの引数? m.emplace(1, 2, 3, 4, 5, 6);
引数の区切りを明確にするためには、それぞれの引数をタプルにパックして転送する必要があります。結果として、std::map
のemplace()
は以下のように使います。
#include <iostream> #include <map> struct X { int a, b, c; X(int a, int b, int c) : a(a), b(b), c(c) {} }; bool operator<(const X& l, const X& r) { return std::tie(l.a, l.b, l.c) < std::tie(r.a, r.b, r.c); } struct Y { Y(int d, int e, int f) {} }; int main() { std::map<X, Y> m; m.emplace( std::piecewise_construct, std::forward_as_tuple(1, 2, 3), // Xのコンストラクタ引数 std::forward_as_tuple(4, 5, 6)); // Yのコンストラクタ引数 }
std::forward_as_tuple()
関数を使うと、tuple<T1&&, T2&&, T3&&...>
のような、右辺値参照のタプルができます。
std::pair
のコンストラクタに、そのようなタプルを展開して各要素を構築するためのオーバーロードが用意されているので、それにおまかせすることになります。pair
のこの構築方法については、以下のエントリを参照: