據我所知,在C++ 11中,通用引用應該始終與std::forward
一起使用,但我不確定如果不使用std::forward
會出現什麼樣的問題。未轉發通用引用會出現什麼樣的問題?
template <T>
void f(T&& x);
{
// What if x is used without std::forward<T>(x) ?
}
您能提供一些在這種情況下可能發生的問題的插圖嗎?
據我所知,在C++ 11中,通用引用應該始終與std::forward
一起使用,但我不確定如果不使用std::forward
會出現什麼樣的問題。未轉發通用引用會出現什麼樣的問題?
template <T>
void f(T&& x);
{
// What if x is used without std::forward<T>(x) ?
}
您能提供一些在這種情況下可能發生的問題的插圖嗎?
有沒有這樣的規則到總是使用std::forward
與普遍引用。相反,在通用參考文獻的功能中使用std::forward
可能是危險的。看看下面的例子:
template <typename T>
auto make_pair(T&& t)
{
return std::make_tuple(std::forward<T>(t), std::forward<T>(t)); // BAD
}
如果調用此函數make_pair(std::string{"foobar"})
,結果是反直覺的,因爲你從同一對象移動兩次。
更新:下面是另一個例子表明,它真的很有意義的使用普遍引用無完美轉發:
template <typename Range, typename Action>
void foreach(Range&& range, Action&& action)
{
using std::begin;
using std::end;
for (auto p = begin(range), q = end(range); p != q; ++p) {
action(*p);
}
}
std::forward
代替範圍或代替動作將是錯誤的。比方說f
被稱爲像這樣:
f(someType{});
如果f
身體上執行x
foo(x);
某種運算並有兩個重載foo
void foo(someType const&);
void foo(someType&&);
不使用std::forward
,作爲x
是一個左值以下過載被稱爲
void foo(someType const&);
這可能會花費你一個潛在的優化。
使用
foo(std::forward<T>(x));
確保的foo
正確超載被選中。
帶名稱的東西是左值。這意味着在函數體中,t
是一個左值。如果通用參考結束爲左值參考或右值參考,則無關緊要。如果它被命名,它是一個左值。
如果您因此直接傳遞該參數,您將傳遞一個左值。
在您只想將不透明參數傳遞給另一個函數的情況下,您想要按原樣傳遞它。如果它是一個左值,你想把它作爲一個左值;如果它是一個右值你想傳遞一個右值。正如所解釋的,直接傳遞它作爲左值總是。 forward
是否需要通過它作爲正確的價值,
總是通過一個左值的代碼可能會受性能的影響,但我會說,當你考慮這個特定的問題時你可以忽略它。有一個更迫切的問題,並不總是通過一個左值:雖然複製某些類型可能很昂貴,但其他類型不能複製的所有,如std::unique_ptr
。對於那些保留右值的類型,當轉發不是性能問題,而是讓你的代碼進行編譯時。
您不應多次轉發變量。
非常好的一點,但它並沒有明確回答「如果不使用std :: forward會出現什麼樣的問題?」的問題。 – Nicolas
+1,但爲什麼將'std :: forward'用於'action'會出錯?我只是讀了這個:[爲什麼使用一個完美轉發的值?](http://stackoverflow.com/q/24779910/873025),並且如果不保留r值,你似乎可能丟掉一個優化機會。 – Snps
@Snps:與'std :: apply'相反,上面的代碼包含一個循環。根據'Action'的類型,'std :: forward(action)'可以與'std :: move(action)'相同。這意味着對於'std :: forward',你可能會在第一次迭代中更改函數對象'action',並導致所有剩餘迭代的奇怪行爲。 –
nosid