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à Example
và arg
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?
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
'" hello "' không phải là 'const char *', nó là 'const char [6]' có thể phân rã thành 'const char *'. . –
^(và không phân rã trong tình huống này) –