2015-10-19 13 views
24

Próbuję zrobić emplace_back w std::vector<std::map<int, int>>, ale nie mogłem znaleźć odpowiedniej składni, aby to zrobić.emplace_back nie działa z std :: wektor <std :: map <int, int>>

#include<map> 
#include<vector> 

int main() 
{ 
    std::vector<std::map<int, int>> v; 
    std::map<int,int> a {{1,2}}; 

    v.push_back({{1,2}}); 

    v.emplace_back({1,2}); // error 
    v.emplace_back({{1,2}}); // error 
    v.emplace_back(({1,2})); // error 
} 

push_back tu pracuje, ale nie emplace_back. Jak mogę uzyskać emplace_back?

+0

Brak. używając tylko nawiasów klamrowych i nawiasów – gjha

+0

Wierzę, że nie przekazujemy skonstruowanych obiektów do emplace_back. – gjha

+0

Istnieje 'v.emplace_back (std :: map {{1,2}}); .. .. nie idealny oczywiście –

Odpowiedz

7

Można to osiągnąć przy użyciu funkcji pomocnika następująco:

#include <map> 
#include <vector> 

void emplace_work_around(
    std::vector<std::map<int, int>>& v, 
    std::initializer_list<std::pair<const int,int>> && item 
) 
{ 
    v.emplace_back(std::forward<std::initializer_list<std::pair<const int,int>>>(item)); 
} 

int main() 
{ 
    std::vector<std::map<int, int>> v; 

    emplace_work_around(v,{{1,2}}); 
} 

Problem był, gdy piszemy:

v.emplace_back({{1,2}}); // here {{1,2}} does not have a type. 

kompilator nie jest w stanie wywnioskować typu argumentu i nie może zdecydować, który konstruktor wywoła.

Ideą jest to, że podczas pisania funkcji takich jak

template<typename T> 
void f(T) {} 

i używać go jak

f({1,2,3,4}); //error 

otrzymasz błąd kompilatora, jak {1,2,3,4} robi mieć typ.

Ale jeśli zdefiniować swoją funkcję jako

template<typename T> 
void f(std::initializer_list<T>) {} 
f({1,2,3,4}); 

następnie kompiluje doskonale.

12

emplace_back przesyła wszystkie argumenty do zgodnego konstruktora typu elementu. Teraz, std::map ma konstruktor listy inicjalizacyjnej, ale oczekuje listy std::pair<const Key, Value>, tj. std::pair<const int, int>. push_back nie jest szablonem, więc oczekuje tylko jednego typu, a zatem wykonuje konwersję w miejscu. Oznacza to, że nie występuje tu odliczanie typu.

Musisz wyraźnie określić, że chcesz mieć std::pair; dodaje powinno działać:

#include<map> 
#include<vector> 

int main() 
{ 
    std::vector<std::map<int, int>> v; 

    v.emplace_back(std::initializer_list<std::pair<const int, int>>{ 
      {1,2},{3,4},{5,6}}); 

    return 0; 
} 

Z tego samego powodu, to nie kompiluje:

v.emplace_back({std::pair<const int,int>(1,2), 
        std::pair<const int,int>(3,4)}); 

To dlatego, że choć lista zamkniętych klamra może przynieść inicjator-list, to nie robi musieć. Może to być również wywołanie konstruktora lub coś podobnego. Tak, pisanie

auto l = {std::pair<const int,int>(1,2), 
      std::pair<const int,int>(3,4)}; 

daje fragment lista initializer dla l, ale sam wyraz może być wykorzystane w inny sposób:

std::pair<std::pair<const int, int>, std::pair<const int, int>> p = 
      {std::pair<const int,int>(1,2), 
      std::pair<const int,int>(3,4)} 

Cały ten materiał staje się trochę niechlujny.

Zasadniczo, jeśli masz listę zamkniętą, może ona przynieść listę inicjalizacyjną lub wywołać odpowiedni konstruktor. Istnieją przypadki, w których kompilator nie jest w stanie określić, które typy są potrzebne; emplace_back jest jednym z nich (ze względu na przekazywanie). W innych przypadkach działa, ponieważ wszystkie typy są zdefiniowane w wyrażeniu. Np .:

#include <vector> 
#include <utility> 

int main() 
{ 
    std::vector<std::pair<const int, int>> v = 
     {{1,2},{3,4},{5,6}}; 
    return 0; 
} 

Powodem, dla którego to nie działa, jest to, że nie można wywnioskować żadnego typu. To znaczy. emplace_back próbuje wyprowadzić nazwę typów wejściowych, ale nie jest to możliwe, ponieważ lista zamknięta zawiera kilka typów, które może opisać. Dlatego nie ma pasującego wywołania funkcji.

+0

Niezupełnie, to ma sens. Trochę skomplikowane jest przekazywanie dalej, ale zawsze możesz napisać standardową propozycję, aby rozwiązać ten problem. To byłoby znacznie bardziej produktywne ... –

+0

Oczywiście nie rozumiesz systemu typu C++. Możliwe, że istnieje rozwiązanie tego problemu, że listy zawierające zamknięcie nie mogą wiązać się z parametrem funkcji szablonowej (co znowu: ma sens, ponieważ nie jest typem), ale ktoś musiałby go zapisać. Problem polega na tym, że w C++ rozdzielczość typu musi wystąpić w czasie kompilacji i dlatego nie działa. To nie jest głupie, ponieważ jest to dobry wybór, aby szybko uczynić język. –

+0

lol w porządku, nie rozumiem systemu typu C++. Czy twoim zwyczajem jest przyjmowanie czyjejś opinii o ekspresji języka i przekształcanie go w zjełczałe, całkowicie niedoinformowane uderzenie w zrozumienie tego, jak język jest skonstruowany technicznie? Jak smutno dla ciebie. Proponuję, aby rzucić okiem na mój profil, zanim przejdziesz dalej swoją małą podróżą z nienawiścią. –

Powiązane problemy