2016-09-02 23 views
5

Uczę się std::forward. Napisałem krótki program do sprawdzenia, co się stanie, jeśli nie nazywamy std::forward przed przekazaniem argumenty do innego wywołania funkcji:Dlaczego łańcuchy C++ nie potrzebują std :: forward, aby wywołać pożądaną funkcję?

#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; 
} 

Tutaj starałem się przekazać lwartość i rvalue z test_forward_wrapper() do test_forward_inner(). Uruchomienie tego programu daje wyjście:

& example 
& example 

& hello 
&& hello 

Dla std::string s, pożądana funkcja wewnętrzna został powołany, ale dla własnej klasy tylko wersja lwartość nazwano. Dopiero po wywołaniu std::forward przed przekazaniem argumentów do funkcji wewnętrznej można wywołać wersję rvalue.

Co robi różnicę tutaj? Jak wiem, zgodnie z referencyjnymi regułami zwijania, gdy opakowanie było wywoływane z Example(), wartość r, T byłaby wydedukowana jako Example i arg miałaby typ Example &&, dlatego powinna zostać wywołana wersja rubliczna funkcji wewnętrznej.

W przypadku innych sytuacji, takich jak tutaj: std::string, została wywołana prawidłowa wersja funkcji wewnętrznej, czy możemy usunąć tutaj kod std::forward? Jeśli nie, to co (może coś złego) się stanie?

Odpowiedz

7

Należy pamiętać, że "hello" nie jest std::string, jest to const char[6]. I test_forward_wrapper() jest szablonem funkcji, argument szablonu T zostanie wydedukowany jako char const (&)[6].

Wewnątrz test_forward_wrapper(), test_forward_inner() jest wywoływane z const char[6], które najpierw trzeba przekonwertować na std::string. Jest to tymczasowa wartość, tj. Wartość, preferowana do powiązania z wartością odniesienia rVV, dlatego wywoływana jest test_forward_inner(string &&).

Przekazanie dokładnego numeru std::string do test_forward_wrapper() spowoduje uzyskanie tego samego wyniku.

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

Różnica polega na tym, że w

test_forward_wrapper("hello"); 

"cześć" tutaj nie jest std::string. To jest const char *.

zmienić to do

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

a wynik będzie taki sam, jak zwyczaj klasa jest.

+1

Ważne jest to, że owijka jest matrycy (a więc nie pojawia się w tym przymus połączenia), przy czym funkcja wewnętrzna nie tylko przyjmowania 'std :: string', co oznacza przemianę' string' zachodzi następnie (podając referencję wartości r do funkcji wewnętrznej), nie ma potrzeby przekazywania. – ShadowRanger

+3

'" cześć "' nie jest 'const char *', jest to 'const char [6]', które może zepsuć się do 'const char *'. . –

+1

^(i nie gnije w tej sytuacji) –