2016-09-02 15 views
5

Tôi đang học std::forward. Tôi đã viết một chương trình ngắn để kiểm tra những gì sẽ xảy ra nếu chúng ta không gọi std::forward trước khi chuyển tiếp các đối số khác gọi hàm:Tại sao chuỗi C++ không cần std :: forward để gọi hàm mong muốn?

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

Ở đây tôi đã cố gắng để chuyển tiếp một vế trái và một rvalue test_forward_wrapper()-test_forward_inner(). Chạy chương trình này cung cấp cho các đầu ra:

& example 
& example 

& hello 
&& hello 

Đối std::string s, chức năng bên trong mong muốn được gọi, nhưng đối với lớp của riêng tôi chỉ có phiên bản giá trị trái được gọi. Chỉ khi tôi gọi std::forward trước khi chuyển các đối số đến hàm bên trong thì phiên bản giá trị có thể được gọi.

Điều gì tạo sự khác biệt ở đây? Như tôi đã biết, theo quy tắc thu gọn tham chiếu, khi trình bao bọc được gọi với Example(), giá trị bằng, T sẽ được suy ra là Examplearg sẽ có loại Example && do đó phiên bản giá trị của hàm bên trong sẽ được gọi.

Và, đối với các trường hợp khác như trường hợp std::string ở đây, phiên bản chính xác của chức năng bên trong đã được gọi, sau đó chúng tôi có thể xóa std::forward tại đây? Nếu không, những gì (có thể là một cái gì đó xấu) sẽ xảy ra?

Trả lời

7

Lưu ý rằng "hello" không phải là std::string, đó là const char[6]. Và test_forward_wrapper() là mẫu chức năng, đối số mẫu T sẽ được khấu trừ là char const (&)[6] cho nó.

Bên trong test_forward_wrapper(), test_forward_inner() được gọi với số const char[6], cần được chuyển đổi thành std::string lúc đầu. Đây là số tạm thời std::string, tức là một giá trị, được ưu tiên ràng buộc với tham chiếu rvalue, đó là lý do tại sao test_forward_inner(string &&) được gọi.

Truyền chính xác std::string đến test_forward_wrapper() sẽ nhận được kết quả tương tự.

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

Sự khác biệt là ở

test_forward_wrapper("hello"); 

"hello" ở đây không phải là một std::string. Đó là const char *.

Thay đổi này cho một người

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

Và kết quả sẽ được giống như các lớp của tùy chỉnh.

+1

Phần quan trọng là trình bao bọc được templated (do đó không có cưỡng chế xảy ra trong cuộc gọi đó), trong khi hàm bên trong không, chỉ chấp nhận 'std :: string', có nghĩa là chuyển đổi thành' chuỗi' xảy ra sau đó (cung cấp tham chiếu giá trị r cho hàm bên trong), không liên quan đến chuyển tiếp. – ShadowRanger

+3

'" hello "' không phải là 'const char *', nó là 'const char [6]' có thể phân rã thành 'const char *'. . –

+1

^(và không phân rã trong tình huống này) –

Các vấn đề liên quan