2016-11-17 16 views
5

Như đã trình bày ở cplusplus.com, std::forward có hai chữ ký:Tại sao có hai chữ ký của std :: forward?

template <class T> T&& forward (typename remove_reference<T>::type& arg) noexcept; 
template <class T> T&& forward (typename remove_reference<T>::type&& arg) noexcept; 

Việc sử dụng điển hình của std::forward là để bảo tồn rvalueness trong khi đi qua các đối số cho các chức năng khác. Hãy minh họa điều này với một ví dụ:

void overloaded(int &) { std::cout << "lvalue"; } 
void overloaded(int &&) { std::cout << "rvalue"; } 

template <typename T> 
void fwd(T && t) 
{ 
    overloaded(std::forward<T>(t)); 
} 

Khi chúng ta gọi là fwd(0), T deduces để int (t đã gõ int &&). Sau đó, chúng tôi gọi số std::forward<int>(t). Kết quả của cuộc gọi đó là biểu thức của loại int && do đó, phiên bản thứ hai của chức năng overloaded được chọn và chương trình in "rvalue" cho đầu ra tiêu chuẩn.

Khi chúng ta gọi là fwd(i) (trong đó i là một số int biến), T deduces để int& (t có kiểu int &). Sau đó, chúng tôi gọi số std::forward<int&>(t). Kết quả của cuộc gọi đó (sau khi áp dụng quy tắc thu gọn tham chiếu) là biểu thức của loại int & do đó phiên bản đầu tiên của chức năng overloaded được chọn và chương trình in "lvalue" vào đầu ra tiêu chuẩn.

Trong cả hai trường hợp này, chúng tôi sử dụng quá tải đầu tiên của std::forward (số chụp typename remove_reference<T>::type& arg). Đó là bởi vì ngay cả khi loại tint && nó liên kết với tham chiếu lvalue (vì biến được đặt tên kiểu "tham chiếu rvalue cho một cái gì đó" là chính nó lvalue và lvalues ​​không thể liên kết với tham chiếu rvalue).

Câu hỏi 1:

rằng tình trạng quá tải thứ hai của std::forward là cái gì? Bạn có thể nghĩ ra một số ví dụ thực tế, sử dụng quá tải tham gia arg theo tham chiếu rvalue?

Câu hỏi 2:

cplusplus.com nói:

Both signatures return the same as:

static_cast<decltype(arg)&&>(arg) 

Tôi có vấn đề với điều đó, là tôi khá chắc chắn rằng nó là sai. Khi chúng tôi cố gắng trả lại điều này từ quá tải đầu tiên của std::forward, chúng tôi sẽ gặp lỗi biên dịch.

Khi fwd được gọi là int rvalue, nó gọi quá tải đầu tiên là std::forward với T = int. Sau đó, decltype(arg) sẽ trở thành int& để static_cast<decltype(arg)&&>(arg) sẽ thu gọn thành static_cast<int&>(arg). Tuy nhiên, kiểu trả về là int && và chúng tôi nhận được lỗi biên dịch:

cannot bind ‘std::remove_reference<int>::type {aka int}’ lvalue to ‘int&&’ 

Cả hai phiên bản quá tải của std::forward nên trở static_cast<T&&>(arg). Tôi có đúng không?

Bạn có nghĩ rằng trích dẫn từ cplusplus.com là nhầm lẫn không?

+0

Xem http://stackoverflow.com/questions/38344332/why-does-stdforward-have-two-overloads để có câu trả lời cho câu hỏi đầu tiên. – TartanLlama

+0

@TartanLlama Cái đó có một bó 'const' và' const_cast' được rải trong suốt tho. – Yakk

+4

'cplusplus.com' là NOT' cppreference'. 'cppreference.com' là' cppreference'. Biết sự khác biệt. – Nawaz

Trả lời

1
class Foo {}; 

auto f = [](){ return Foo{}; }; 
auto g = []()->Foo&{ static Foo x; return x; }; 

template<class T> 
std::false_type is_rvalue(T&) { return {}; } 
template<class T> 
std::true_type is_rvalue(T&&) { return {}; } 

template<class T, class F> 
auto test(F&& f) { 
    return is_rvalue(std::forward<T>(f())); 
} 

int main() { 
    std::cout << test<Foo>(f) << "," << test<Foo&>(g) << "\n"; 
} 

Đó là một chút giả tạo; nhưng hãy tưởng tượng nơi bạn có một số nhà máy có thể sản xuất Foo hoặc Foo& tùy thuộc vào một số chi tiết không quan trọng, nhưng bạn biết bạn muốn chuyển tiếp nó dựa trên loại thứ hai T đến T&&. Bạn biết rằng nếu T không phải là tham chiếu, thì nó sẽ không sản xuất Foo, nhưng nếu T là một tham chiếu có thể.

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