2012-03-09 21 views
68

Właśnie grałem z g ++ 4.7 (jedną z późniejszych migawek) z włączoną opcją -std = C++ 11. Próbowałem skompilować część istniejącej bazy kodu i jedna sprawa, która się nie powiodła, nieco mnie zakłopotała.C++ 11 make_par z określonymi parametrami szablonu nie kompiluje się

Byłbym wdzięczny, gdyby ktoś mógł wyjaśnić, co się dzieje.

Oto kod

#include <utility> 
#include <iostream> 
#include <vector> 
#include <string> 

int main () 
{ 
    std::string s = "abc"; 

    // 1 ok 
    std::pair < std::string, int > a = std::make_pair (s, 7); 

    // 2 error on the next line 
    std::pair < std::string, int > b = std::make_pair < std::string, int > (s, 7); 

    // 3 ok 
    std::pair < std::string, int > d = std::pair < std::string, int > (s, 7); 

    return 0; 
} 

Rozumiem, że make_pair jest oznaczało być stosowany jako (1) sprawy (jeśli określić typy, to równie dobrze można użyć (3)), lecz Nie rozumiem, dlaczego w tym przypadku nie działa.

Dokładny błędu:

test.cpp: In function ‘int main()’: test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’ test.cpp:11:83: note: candidate is: In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0, from test.cpp:1: /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template constexpr std::pair::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template argument deduction/substitution failed: test.cpp:11:83: note: cannot convert ‘s’ (type ‘std::string {aka std::basic_string}’) to type ‘std::basic_string&&’

Znowu tutaj pytanie jest po prostu „co się dzieje?” Wiem, że mogę rozwiązać ten problem, usuwając specyfikację szablonu, ale chcę tylko wiedzieć, co się tu nie udaje pod kołdrą. Z góry dziękuję.

EDIT:

  • g ++ 4.4 kompiluje kod bez żadnych problemów.
  • Usuwanie -std = C++ 11 również kompiluje się z kodem bez żadnych problemów.
+5

doskonałe pytanie. Kolejny przykład subtelnej zmiany w C++ 11, podobnie jak [zmiana zerwania konstrukcji 'std :: vector'] (http://stackoverflow.com/questions/5759232/stdvector-default-construction-c11- i łamanie zmian). Przynajmniej ten powoduje błąd kompilatora, a nie cichą zmianę semantyki. –

+1

Jeśli mam zmienną całkowitą i. Chcę utworzyć parę z i i innym obiektem. Jak dokładnie powinienem nazywać makepair. 1) make_pair <*i, obj> 2) int && j = i; make_pair ? Oba nie działają. Co to jest właściwy sposób? – PHcoDer

Odpowiedz

108

To nie jest sposób użycia std::make_pair; nie należy jawnie określać argumentów szablonu.

C++ 11 std::make_pair przyjmuje dwa argumenty typu T&& i U&&, gdzie T i U są parametry typu szablonu. Skutecznie, wygląda to tak (pomijając typ zwracany):

template <typename T, typename U> 
[return type] make_pair(T&& argT, U&& argU); 

Po wywołaniu std::make_pair i wyraźnie określić argumenty typu szablonu, bez odliczenia argumentem odbywa. Zamiast tego, argumenty typu są podstawione bezpośrednio w deklaracji szablonu, otrzymując:

[return type] make_pair(std::string&& argT, int&& argU); 

Zauważ, że oba te typy parametrów są referencje rvalue. W związku z tym mogą wiązać się tylko z wartościami r. Nie stanowi to problemu dla drugiego argumentu, który przekazujesz, 7, ponieważ jest to wyrażenie rvalue. s jest jednak wyrażeniem l-wartościowym (nie jest tymczasowe i nie jest przenoszone). Oznacza to, że szablon funkcji nie pasuje do twoich argumentów, dlatego pojawia się błąd.

Dlaczego więc działa, gdy nie podano wyraźnie, co T i U znajduje się na liście argumentów szablonu? W skrócie, parametry referencyjne rvalue są specjalne w szablonach. Częściowo z powodu funkcji językowej o nazwie , która zawijała się pod numerem, parametr wartości odniesienia rVr typu A&&, gdzie A jest parametrem typu szablonu, może być powiązany z dowolnym rodzajem A.

To nie ma znaczenia, czy A jest lwartością, rvalue, const kwalifikowaną, lotny wykwalifikowanych lub niewykwalifikowanych, A&& może wiązać się z tego przedmiotu (ponownie, wtedy i tylko wtedy A sama jest parametrem szablonu).

W przykładzie, wykonujemy połączenia:

make_pair(s, 7) 

Tutaj s jest lwartością typu std::string i 7 jest rvalue typu int. Ponieważ nie określa się argumentów szablonu dla szablonu funkcji, wykonywane jest odliczanie argumentów w szablonie, aby dowiedzieć się, jakie są argumenty.

Aby związać s, lwartością, aby T&& kompilator wyprowadza T być std::string& otrzymując argumentu typu std::string& &&. Nie ma jednak odniesień do referencji, więc ten "podwójny odnośnik" upada, aby stać się std::string&. s to mecz.

Łatwo jest powiązać 7 do U&&: kompilator może wywnioskować U być int uzyskując parametr typu int&&, który wiąże się z powodzeniem 7 ponieważ jest RValue.

Istnieje wiele subtelności z tych nowych funkcji językowych, ale jeśli się jedną prostą zasadę, to całkiem proste:

If a template argument can be deduced from the function arguments, let it be deduced. Don't explicitly provide the argument unless you absolutely must.

Let the compiler do the hard work, and 99.9% of the time it'll be exactly what you wanted anyway. When it isn't what you wanted, you'll usually get a compilation error which is easy to identify and fix.

+6

To jest bardzo dobre i wyczerpujące wyjaśnienie. Dziękuję Ci! – vmpstr

+1

@James - czy to "jedna prosta zasada" z innego artykułu lub odpowiedzi, którą powinienem przeczytać? –

+4

@MichaelBurr: Nie, właśnie to wymyśliłem. :-) Mam nadzieję, że to prawda! Myślę, że to prawda ... ta zasada działa dla mnie przez cały czas. –

Powiązane problemy