2016-09-02 7 views
5

Ich lerne std::forward. Ich schrieb ein kleines Programm zu testen, was passieren würde, wenn wir nicht std::forward nennen, bevor die Argumente an einem anderen Funktion Anrufweiterschaltung:Warum C++ - Zeichenfolgen brauchen nicht std :: forward, um die gewünschte Funktion aufzurufen?

#include <iostream> 
#include <typeinfo> 
#include <string> 
using namespace std; 

class Example { 
}; 

ostream &operator << (ostream &os, const Example &e) { os << "yes!"; return os; } 

void test_forward_inner(const Example &e) { cout << "& " << e << endl; } 
void test_forward_inner(Example &&e) { cout << "&& " << e << endl; } 

void test_forward_inner(const string &e) { cout << "& " << e << endl; } 
void test_forward_inner(string &&e) { cout << "&& " << e << endl; } 

template <typename T> 
void test_forward_wrapper(T &&arg) { 
    test_forward_inner(arg); 
} 

int main() 
{ 
    Example e; 
    test_forward_wrapper(e); 
    test_forward_wrapper(Example()); 

    cout << endl; 

    string s("hello"); 
    test_forward_wrapper(s); 
    test_forward_wrapper("hello"); 

    return 0; 
} 

Hier habe ich versucht, einen L-Wert und einen R-Wert test_forward_wrapper()-test_forward_inner() zu übermitteln. Das Ausführen dieses Programms gibt die Ausgabe:

& example 
& example 

& hello 
&& hello 

Für std::string s wurde die gewünschte innere Funktion genannt, aber für meine eigene Klasse wurde nur die L-Wert-Version genannt. Nur wenn ich rufe, bevor die Argumente an die innere Funktion übergeben werden, kann die rvalue-Version aufgerufen werden.

Was macht hier den Unterschied? Wie ich weiß, würde gemäß den Regeln zum Kollabieren von Referenzen, wenn der Wrapper mit Example() aufgerufen wurde, ein rvalue, T als Example abgeleitet werden und arg würde den Typ Example && haben, daher sollte die rvalue-Version der inneren Funktion aufgerufen werden.

Und für andere Situationen wie der std::string Fall hier, wurde die richtige Version der inneren Funktion aufgerufen, dann können wir die std::forward hier entfernen? Wenn nicht, was (vielleicht etwas Schlechtes) würde passieren?

Antwort

7

Beachten Sie, dass "hello" nicht std::string ist, es ist ein const char[6]. Und test_forward_wrapper() ist eine Funktionsvorlage, die Vorlage Argument T wird als char const (&)[6] dafür abgeleitet werden.

Innen test_forward_wrapper() wird test_forward_inner() mit const char[6] genannt, die std::string zunächst konvertiert werden müssen. Dies ist ein temporärer std::string, d. H. Ein R-Wert, der bevorzugt an die R-Referenz gebunden ist, weshalb test_forward_inner(string &&) aufgerufen wird.

Eine genaue std::string zu test_forward_wrapper() übergeben wird das gleiche Ergebnis erhalten.

test_forward_wrapper(std::string("hello")); 
4

Der Unterschied ist, dass in

test_forward_wrapper("hello"); 

"Hallo" hier ist kein std::string. Es ist ein const char *.

Ändern Sie diese zu einem

test_forward_wrapper(std::string("hello")); 

und das Ergebnis wird die gleiche wie die benutzerdefinierte Klasse sein.

+1

Der wichtige Teil ist, dass die Wrapper-templated ist (so dass kein Zwang in diesem Anruf auftritt), während die innere Funktion nicht der Fall ist, nur 'std :: string' zu akzeptieren, die die Umwandlung zu' string' bedeutet auftritt dann (Bereitstellung eines r-Wert Verweises auf die innere Funktion), keine Weiterleitung beteiligt. – ShadowRanger

+3

'" Hallo "' ist kein 'const char *', es ist ein 'const char [6]', das in ein 'const char *' zerfallen kann. . –

+1

^(und zerfällt in dieser Situation nicht) –

Verwandte Themen