2015-02-20 2 views
2

Задача

У меня есть std::map<int, std::set<int>> по имени misi. Мне интересно, почему misi.emplace(2345, {6, 9}); и misi.emplace({2345, {6, 9}}); не работают должным образом, как показано ниже.Как использовать emplace() в std :: map, значение которого является std :: set (карта от чего-то к набору)?

Кодекс

#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::map из 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 

Для 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 

ответ

4

списки приготовился инициализатора не имеют типа, поэтому они не могут быть полностью перенаправлены. В данном конкретном случае, вы можете указать тип (std::initializer_list<int>) явно, если вы хотите, чтобы весь быть построена на месте:

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

Поскольку только один аргумент каждого передаются для ключа и значения, и initializer_list конструктора std::set не explicit, вы можете удалить piecewise_construct вообще и есть emplace построить pair используя конструктор, принимающий два аргумента:

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

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

Интересно, если std :: pair построена на месте или нет. (Ну, я думаю, не )

Нет, временный std::pair<int, int> построен и передан emplace, который создает экземпляр из map «s value_type (который pair<const int, int>) с ним. Последнее - это то, что фактически хранится в map.


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

, кажется, что создается станд :: набор на месте (правильно?).

No. Опять же, это создает временную std::pair<int, std::set<int>>, а затем строит то, что на самом деле хранится в map (который pair<const int, std::set<int>>) с ним. Эта вторая конструкция выполнит переход от set<int>, сохраненного во временном порядке.

+0

Спасибо большое! Я потратил несколько часов, чтобы понять, как это сделать! Теперь я использую 'misi.emplace (2345, std :: initializer_list {6, 9});' который компилируется отлично! –

+0

@ SiuChingPong-AsukaKenji- Да, вам действительно не нужно использовать 'кусочек_конструкции' здесь. –

Смежные вопросы