Ich habe gerade mit g ++ 4.7 (einem der späteren Schnappschüsse) mit aktiviertem -std = c ++ 11 herumgespielt. Ich habe versucht, einen Teil meiner vorhandenen Codebasis zu kompilieren, und ein fehlgeschlagener Fall verwirrt mich etwas.
Ich würde mich freuen, wenn jemand erklären kann, was los ist.
Hier ist der Code:
#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;
}
Ich verstehe , dass make_pair ist gemeint als (1) Fall verwendet werden (wenn ich die Typen angeben, dann könnte ich auch verwenden (3)), aber ich verstehe nicht, warum es in diesem Fall versagt.
Der genaue Fehler ist:
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<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_T1>::__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<char>}’) to type ‘std::basic_string<char>&&’
Auch hier lautet die Frage nur: "Was ist los?" Ich weiß, dass ich das Problem beheben kann, indem ich die Vorlagenspezifikation entferne, aber ich möchte nur wissen, was hier unter der Decke fehlschlägt.
- g ++ 4.4 kompiliert diesen Code ohne Probleme.
- Das Entfernen von -std = c ++ 11 wird auch problemlos mit Code kompiliert.
std::vector
Konstruktion . Zumindest dieser ergibt einen Compilerfehler und keine stille Änderung der Semantik.Antworten:
So
std::make_pair
soll es nicht verwendet werden; Sie sollten die Vorlagenargumente nicht explizit angeben.C ++ 11 verwendet
std::make_pair
zwei Argumente vom TypT&&
undU&&
, wobeiT
undU
Vorlagentypparameter sind. Tatsächlich sieht es so aus (ohne Rückgabe):Wenn Sie
std::make_pair
die Argumente des Vorlagentyps aufrufen und explizit angeben, findet kein Argumentabzug statt. Stattdessen werden die Typargumente direkt in die Vorlagendeklaration eingesetzt, was Folgendes ergibt:Beachten Sie, dass diese beiden Parametertypen rWertreferenzen sind. Sie können also nur an r-Werte binden. Dies ist kein Problem für das zweite Argument, das Sie übergeben
7
, da dies ein r-Wert-Ausdruck ist.s
Es handelt sich jedoch um einen l-Wert-Ausdruck (er ist kein temporärer Ausdruck und wird nicht verschoben). Dies bedeutet, dass die Funktionsvorlage nicht mit Ihren Argumenten übereinstimmt, weshalb Sie den Fehler erhalten.Warum funktioniert es also, wenn Sie nicht explizit angeben, was
T
undU
in der Vorlagenargumentliste enthalten sind? Kurz gesagt, r-Wert-Referenzparameter sind in Vorlagen speziell. Zum Teil aufgrund einer Sprachfunktion, die als Referenzkollabieren bezeichnet wird , kann ein rvalue-Referenzparameter vom TypA&&
, bei demA
es sich um einen Vorlagentypparameter handelt, an jede Art von gebunden werdenA
.Es spielt keine Rolle, ob
A
es sich um einen l-Wert, einen r-Wert, einen const-qualifizierten, einen flüchtigen oder einen nicht qualifizierten Wert handelt, derA&&
an dieses Objekt gebunden werden kann (wiederum genau dann, wennA
es sich selbst um einen Vorlagenparameter handelt).In Ihrem Beispiel rufen wir an:
Hier
s
ist ein Wert vom Typstd::string
und7
ein Wert vom Typint
. Da Sie die Vorlagenargumente für die Funktionsvorlage nicht angeben, wird der Vorlagenargumentabzug durchgeführt, um die Argumente herauszufinden.Zu binden
s
, ein L - Wert, umT&&
die Compiler folgern,T
zu seinstd::string&
, ein Argument des Typs ergibtstd::string& &&
. Es gibt jedoch keine Verweise auf Referenzen, so dass diese "Doppelreferenz" zusammenbricht, um zu werdenstd::string&
.s
ist ein Match.Es ist einfach zu binden
7
anU&&
: der Compiler kann ableitenU
zu seinint
, einen Parameter des Typs ergibtint&&
, die erfolgreich bindet ,7
weil es ein R - Wert ist.Es gibt viele Feinheiten bei diesen neuen Sprachfunktionen, aber wenn Sie eine einfache Regel befolgen, ist es ziemlich einfach:
quelle