2016-11-17 34 views
5

截至cplusplus.com指出,std::forward有兩個特徵:爲什麼有兩個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; 

的典型用途std::forward是維護rvalueness而通過其他函數的參數。讓我們來說明這一個例子:

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

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

當我們調用fwd(0)T演繹到intt的類型爲int &&)。然後我們撥打std::forward<int>(t)。該調用的結果是int &&類型的表達式,因此選擇第二個版本的overloaded函數,程序將「右值」輸出到標準輸出。

當我們調用fwd(i)(其中,i是一些int變量),T推斷到int&t具有類型int &)。然後我們撥打std::forward<int&>(t)。該調用的結果(在應用參考摺疊規則之後)是int &類型的表達式,因此選擇overloaded函數的第一個版本,並且程序將「左值」打印到標準輸出。

在這兩種情況下,我們使用std::forward(取typename remove_reference<T>::type& arg)的第一個過載。這是因爲即使t的類型爲int &&,它也會綁定到左值引用(因爲類型「右值引用某個元素」的名稱變量本身是左值,左值不能綁定右值引用)。

問題1:

那是什麼的std::forward秒過載?你能想到一個實際的例子,它使用了右值參考arg的過載。

問題2:

cplusplus.com說:

Both signatures return the same as:

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

我有這個問題,是,我敢肯定,這是錯誤的。當我們嘗試從std::forward的第一個重載中返回時,我們得到一個編譯錯誤。

fwd被調用int右值時,它會調用std::forward的第一個重載與T = int。然後,decltype(arg)將變爲int&,因此static_cast<decltype(arg)&&>(arg)將摺疊爲static_cast<int&>(arg)。但是,返回類型爲int &&,我們得到的編譯錯誤:

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

std::forward兩個重載版本應該返回static_cast<T&&>(arg)。我對嗎?

你認爲cplusplus.com的報價是錯誤的嗎?

+0

有關第一個問題的答案,請參見http://stackoverflow.com/questions/38344332/why-does-stdforward-have-two-overloads。 – TartanLlama

+0

@TartanLlama那個有一堆'const'和'const_cast'灑在整個tho。 – Yakk

+4

'cplusplus.com'不是'cppreference'。 'cppreference.com'是'cppreference'。知道區別。 – Nawaz

回答

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

這是有點人爲的;但想象你在哪裏有一些工廠,可能會產生一個FooFoo&取決於一些不重要的細節,但你知道你想轉發它基於第二種類型TT&&。你知道如果T不是參考,那麼它不會產生Foo,但是如果T是可能的參考。

相關問題