2010-08-28 60 views
19

如果你有這個功能完美轉發在C++ 03

template<typename T> f(T&); 

,然後嘗試調用它,比方說像

f(1); 

爲什麼右值不是T只是推斷爲const int,使參數爲const int &並因此可綁定到右值?

回答

18

這被提及爲the document中的一個潛在解決方案,我在recent C++0x forwarding question中鏈接了我。

工作得很好,但它破壞了現有的代碼。考慮(直接從文件):

template<class A1> void f(A1 & a1) 
{ 
    std::cout << 1 << std::endl; 
} 

void f(long const &) 
{ 
    std::cout << 2 << std::endl; 
} 

int main() 
{ 
    f(5);    // prints 2 under the current rules, 1 after the change 
    int const n(5); 
    f(n);    // 1 in both cases 
} 

或者

// helper function in a header 

template<class T> void something(T & t) // #1 
{ 
    t.something(); 
} 

// source 

#include <vector> 

void something(bool) // #2 
{ 
} 

int main() 
{ 
    std::vector<bool> v(5); 

    // resolves to #2 under the current rules, #1 after the change 
    something(v[0]); 
} 

這也無法轉發的價值類別(左值或右值),這是沒有太大的C++ 03的問題。但由於此修復只能在C++ 0x期間完成,因此在轉發時(壞事情),我們會有效地將自己從rvalue引用中關閉。我們應該爭取更好的解決方案。

1

這是,但只有當你宣佈f採取T const &

template <typename T> void f(T &); 
template <typename T> void g(T const &); 

void x() { f(1); } // error: invalid initialization of non-const reference 
void y() { g(1); } // no error 

如果你聲明f(T &)f(T const &),它會選擇const限定一個:

template <typename T> void f(T &); 
template <typename T> void f(T const &); 

void x() { f(1); } // no error, calls f(T const &) 

現在,也許你說「在第一個例子,爲什麼它生成一個int類型的臨時文件f,當它可能已經生成了const int類型的臨時文件,並使代碼編譯? 」我給你的最佳答案是,當參數不是整數常量時,這與重載解析行爲不一致。

+0

是的,我知道超載。我想知道爲什麼甚至有必要。它會如何不一致? – Puppy 2010-08-28 18:16:20

+0

@DeadMG:'1'的類型爲'int'。如果你聲明瞭一個'int i = 1',那麼它會選擇非const方法,因爲'i'不是const。因此,爲了一致性,它也是這樣,除了對於右值而言,這是一個錯誤。 – 2010-08-29 11:13:54

+0

@Matthieu:1是一個int rvalue。我是一個整數左值。由於語言堅持以不同的方式對待他們,所以他們是不同的東西。因此,這並不矛盾。事實上,有一些專門針對右值的規則是不一致的,然後在這裏嘗試對待它們。 – Puppy 2010-08-29 11:28:53