4

問題

というstd::map<int, std::set<int>>名前がありmisiます。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;

上記はstd::mapto のintものintで、メソッドも完全に機能することがわかりますが、最後の例では、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

astd::mapから a の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
4

1 に答える 1

6

ブレース付きの初期化子リストには型がないため、完全に転送することはできません。この特定のケースでは、std::initializer_list<int>すべてをその場で構築したい場合は、型 ( ) を明示的に指定できます。

misi.emplace(
  std::piecewise_construct,
  std::forward_as_tuple(2345),
  std::forward_as_tuple(std::initializer_list<int>{6, 9})
);

キーと値にはそれぞれ 1 つの引数のみが渡され、のinitializer_listコンストラクターstd::setは notであるため、を完全にexplicit削除して、2 つの引数を取るコンストラクターを使用してを構築することができます。piecewise_constructemplacepair

misi.emplace(
  2345,
  std::initializer_list<int>{6, 9}
);

mii.emplace(std::pair<int, int>(2345, 6));

std::pair がインプレースで構築されているかどうかは疑問です。(まあ、そうではないと思います)

いいえ、テンポラリstd::pair<int, int>が構築されて に渡され、それを使用してのemplaceインスタンス(これは です) が構築されます。後者は、実際に に格納されているものです。mapvalue_typepair<const int, int>map


misi.emplace(std::pair<int, std::set<int>>(2345, {6, 9}));

std::set がインプレースで作成されているようです (右?)。

繰り返しますが、これは一時的な を作成し、std::pair<int, std::set<int>>実際に に格納されているものmap(つまりpair<const int, std::set<int>>) を構築します。この 2 番目の構造はset<int>、一時的に格納されたものからの移動を実行します。

于 2015-02-20T17:06:09.533 に答える