考慮下面的代碼,其中,相同的附圖被轉發兩次基類,並用於有構造元組:C++多箇中的一個參考轉發:第一拷貝,然後移動
template<typename ... Ts>
struct Base
{
template<typename ... _Ts>
Base(_Ts&& ... ts) : tup{std::forward<_Ts>(ts) ...} {}
std::tuple <Ts ...> tup;
};
template<typename T>
struct Derived : public Base<T, T>
{
template<typename _T>
Derived(_T&& t) : Base<T, T>{t, std::forward<_T>(t)} {}
};
第一主叫基類的構造在Derived
作爲Base<T, T>{t, std::forward<_T>(t)}
並且此後也使用tup{std::forward<Ts>(ts)...}
元組構造函數有以下原因:
當t
是一個rvalue參考,第一元組參數應被傳遞的左值-裁判t
,從而通過一個被構造警察y的t
,而第二個元組元素應該得到一個右值ref,因此,如果可能的話,使用移動來構建。
這種方法似乎得到SO上的幾個問題和答案的支持(例如here,here和here),其中陳述了braced-init列表執行對其參數的從左到右的評估。
然而,當我在一個簡單的例子使用上面的代碼中,實際行爲是(一致)的我的預期相反:
struct A
{
A() = default;
A(A const& other) : vec(other.vec) { std::cout<<"copy"<<std::endl; }
A(A && other) : vec(std::move(other.vec)) { std::cout<<"move"<<std::endl; }
std::vector<int> vec = std::vector<int>(100);
};
int main()
{
Derived<A> d(A{}); //prints first "move", then "copy"
std::cout<<std::get<0>(d.tup).vec.size()<<std::endl; //prints 0
std::cout<<std::get<1>(d.tup).vec.size()<<std::endl; //prints 100
}
這裏是the example using gcc on Coliru。 (gcc編譯器顯然有在這方面的錯誤一次,但它是兩年左右,因爲應該沒什麼問題了。)
問題:
- 我在哪裏錯了就執行或在這裏的假設?
- 如何修復上述代碼以達到預期效果:第一次複製 - 然後移動?
任何符號開頭一個下劃線後面跟着一個大寫字母,用於執行;把'_T'和'_Ts'改成別的東西。 –