2016-09-12 45 views
0

請考慮下面的程序:包擴展變量如何不被引用傳遞?

#include <iostream> 


template <typename T, typename ...Ts> 
struct Foo { 
    template <typename ...Us> 
    static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us... args) { 
     std::cout << " -> Foo<...>::bar() enter [ " << oT0 << ", " << oT1 << " ]" << std::endl; 
     Foo<T>::bar(oT0, oT1, iT0, iT1); 
     Foo<Ts...>::bar(args...); 
     std::cout << " <- Foo<...>::bar() exit [ " << oT0 << ", " << oT1 << " ]" << std::endl; 
    } 
}; 

template <typename T> 
struct Foo<T> { 
    static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1) { 
     std::cout << " -> Foo<>::bar() enter [ " << oT0 << ", " << oT1 << " ]" << std::endl; 
     oT0 = iT0; 
     oT1 = iT1; 
     std::cout << " <- Foo<>::bar() exit [ " << oT0 << ", " << oT1 << " ]" << std::endl; 
    } 
}; 


int main() { 
    int i0 = -1, 
     i1 = 0; 
    float f0 = -97.18f, 
      f1 = 3.141592f; 
    std::cout << "("<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << ") " << std::endl; 

    Foo<int, float, int>::bar(i0, i1, 0, 1, f0, f1, 18.f, -7.f, i0, i1, 4, 17); 
    std::cout << "("<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << ") " << std::endl; 

    Foo<float>::bar(f0, f1, 18.f, -7.f); 
    std::cout << "(" << f0 << ", " << f1 << ") " << std::endl; 

    Foo<float, int>::bar(f0, f1, 2.71f, 9000.1f, i0, i1, 4, 17); 
    std::cout << "("<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << ") " << std::endl; 

    return 0; 
} 

而且其評價輸出(調試輸出去除清晰但可在IDEone):

(-1, 0; -97.18, 3.14159) // initial values 
(0, 1; -97.18, 3.14159) // ints only set once?! floats unchanged?! 
(18, -7) 
(0, 1; 2.71, 9000.1) // ints unchanged?! 

我必須缺少的東西在這裏很明顯:從上面的,調用Foo<...>::bar(...)僅修改第一組兩個非常量參數。爲什麼在main之內的下一個參數值保持不變?

+0

你是否已經介入調試器? – Steve

+4

你的意思是'我們...... args'而不是'Us ... args'嗎? –

+3

@JasonC'我們&& ... args',真的。它也需要處理常量左值 – jaggedSpire

回答

4

您需要在模板的可變參數部分使用引用或超出前四個參數的參數將通過值傳遞給初始調用(複製到局部變量)。隨後的調用會改變這些複製的值,而不是傳遞的原始參數。

既然您想接受某些參數的rvalues,use perfect forwarding for varargs來保留原始類型。只要改變:

static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us... args) { 

到:

// Receive varargs as forwarding references to allow perfect forwarding instead 
// of receiving them as copies 
static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us&&... args) { 

和變化:

Foo<Ts...>::bar(args...); 

到:

// Per earlier link, must explicitly template std::forward call in varargs case 
Foo<Ts...>::bar(std::forward<Us>(args)...); 

應該接受並正確轉發的可變參數,所以他們是無論如何,都會在嵌套調用中收到鍵入(const或非const參考)最內層的「真實」呼叫需要。

+0

我以爲我掌握了各種各樣的模板,事實證明我有更多的閱讀工作要做..謝謝。 – dummydev