2011-12-01 36 views
18

Tại sao đoạn mã sau hợp lệ:Tại sao chức năng chuyển tiếp hoàn hảo phải được tạo mẫu?

template<typename T1> 
void foo(T1 &&arg) { bar(std::forward<T1>(arg)); } 

std::string str = "Hello World"; 
foo(str); // Valid even though str is an lvalue 
foo(std::string("Hello World")); // Valid because literal is rvalue 

Nhưng không:

void foo(std::string &&arg) { bar(std::forward<std::string>(arg)); } 

std::string str = "Hello World"; 
foo(str); // Invalid, str is not convertible to an rvalue 
foo(std::string("Hello World")); // Valid 

Tại sao không phải là giá trị trái trong ví dụ 2 được giải quyết trong cùng một cách thức mà nó trong ví dụ 1?

Ngoài ra, tại sao tiêu chuẩn cảm thấy cần phải cung cấp loại đối số trong std :: forward so với simple deducing it? Chỉ cần gọi về phía trước là hiển thị ý định, bất kể loại nào.

Nếu đây không phải là một điều tiêu chuẩn và chỉ trình biên dịch của tôi, tôi đang sử dụng msvc10, điều này sẽ giải thích sự hỗ trợ C++ 11 crappy.

Cảm ơn

Sửa 1: Thay đổi chữ "Hello World" được std :: string ("Hello World") để thực hiện một rvalue.

+0

Điều gì xảy ra trong thanh? Biên dịch không có nghĩa là nó hoạt động nhất thiết. Tôi tin rằng nó phải là 'void foo (T1 & arg)' và 'void foo (std :: string & arg)' tương ứng. – AJG85

+1

'" Hello World "' không phải là một rvalue, nó là một lvalue với kiểu 'const char [12]'. – GManNickG

+0

@ AJG85 Điều gì xảy ra trong quán bar không quan trọng. && có nghĩa là tham chiếu rvalue. – Mranz

Trả lời

15

Trước hết, read this để có ý tưởng chuyển tiếp đầy đủ. (Có, tôi đang ủy quyền hầu hết các câu trả lời này ở nơi khác.)

Để tóm tắt, chuyển tiếp có nghĩa là các giá trị giữ nguyên giá trị và giá trị giữ nguyên giá trị. Bạn không thể làm điều đó với một loại duy nhất, vì vậy bạn cần hai. Vì vậy, đối với mỗi đối số được chuyển tiếp, bạn cần hai phiên bản cho đối số đó, yêu cầu tổng số kết hợp là 2 N cho hàm. Bạn có thể mã tất cả các kết hợp của hàm, nhưng nếu bạn sử dụng mẫu thì các kết hợp khác nhau sẽ được tạo cho bạn khi cần.


Nếu bạn đang cố gắng để tối ưu hóa các bản sao và di chuyển, chẳng hạn như trong:

struct foo 
{ 
    foo(const T& pX, const U& pY, const V& pZ) : 
    x(pX), 
    y(pY), 
    z(pZ) 
    {} 

    foo(T&& pX, const U& pY, const V& pZ) : 
    x(std::move(pX)), 
    y(pY), 
    z(pZ) 
    {} 

    // etc.? :(

    T x; 
    U y; 
    V z; 
}; 

Sau đó, bạn nên dừng lại và làm điều đó theo cách này:

struct foo 
{ 
    // these are either copy-constructed or move-constructed, 
    // but after that they're all yours to move to wherever 
    // (that is, either: copy->move, or move->move) 
    foo(T pX, U pY, V pZ) : 
    x(std::move(pX)), 
    y(std::move(pY)), 
    z(std::move(pZ)) 
    {} 

    T x; 
    U y; 
    V z; 
}; 

Bạn chỉ cần một constructor. Hướng dẫn: nếu bạn cần bản sao dữ liệu của riêng mình, hãy tạo bản sao đó trong danh sách tham số; điều này cho phép quyết định sao chép hoặc di chuyển đến người gọi và trình biên dịch.

+1

Vì vậy, lý do ví dụ đầu tiên hoạt động là vì T1 thực sự được giải quyết tương đương với 'void foo (const std :: string & && arg)' được giảm xuống 'void foo (const std :: string & arg)' bằng cách sử dụng tham chiếu quy tắc khấu trừ? Nó không thành công trong ví dụ 2 vì không có quá tải lvalue cho chuỗi? Có bất kỳ thực hành tốt nhất nào để xác định hàm mẫu sao cho ít nhất là tương đối rõ ràng loại nào nên là? Lý tưởng nhất là tôi đang tìm kiếm một cách tốt để được rõ ràng với các loại trong khi tránh 2^N quá tải. – Mranz

+1

@Mranz: Chính xác. Vâng, bạn sẽ làm gì? Chuyển tiếp và các mẫu có nghĩa là để được sử dụng để chuyển tiếp, bạn không thực sự cần phải biết các loại. – GManNickG

+0

Cho phép nói rằng tôi có một hàm tạo trong vector như 'Lớp (.. một số args ..., vector mục)'. Lý tưởng nhất, tôi muốn cho phép đối số đó tránh được bản sao bằng cách sử dụng ngữ nghĩa di chuyển hoặc là một giá trị. Để hỗ trợ điều đó, tôi sẽ phải lấy mẫu ra các mục, hoặc tạo ra một quá tải rvalue. Nếu tôi mẫu nó ra, loại thực tế bị mất ở định nghĩa, và đối số thực tế sẽ phải được suy ra bởi người tiêu dùng của lớp của tôi bằng cách đọc tập tin tiêu đề hoặc một số bình luận. – Mranz

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