2011-02-18 27 views
4

它是Visual C++ 2010中的錯誤還是正確的行爲?Visual C++ 2010,右值引用錯誤?

template<class T> 
T f(T const &r) 
{ 
    return r; 
} 

template<class T> 
T f(T &&r) 
{ 
    static_assert(false, "no way"); //< line # 10 
    return r; 
} 

int main() 
{ 
    int y = 4; 
    f(y); //< line # 17 
} 

我想,函數f(T & &)不應該被調用,但它被稱爲與T = INT &。輸出:

 
    main.cpp(10): error C2338: no way 
      main.cpp(17) : see reference to function template instantiation 'T f(T)' being compiled 
      with 
      [ 
       T=int & 
      ] 

更新1你知道的任何C++編譯器X0作爲參考?我已經嘗試了comeau在線試駕,但無法編譯r值參考。

更新2解決方法(使用SFINAE):

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_reference.hpp> 

template<class T> 
T f(T &r) 
{ 
    return r; 
} 

template<class T> 
typename ::boost::disable_if< ::boost::is_reference<T>, T>::type f(T &&r) 
{ 
    static_assert(false, "no way"); 
    return r; 
} 

int main() 
{ 
    int y = 4; 
    f(y); 
    // f(5); // generates "no way" error, as expected. 
} 

更新3編譯器的一些觸發static_assert(假的, 「沒有辦法」),即使沒有函數模板實例。解決方法(感謝@Johannes紹布 - litb)

template<class T> struct false_ { static bool const value = false; }; 
... 
static_assert(false_<T>::value, "no way"); 

static_assert(sizeof(T) == sizeof(T), "no way"); 
+1

我不知道這是否是Visual c + +的特點,`static_assert(false,...)`不總是觸發?在G ++中,斷言必須依賴於模板參數才能觸發,除非函數被實例化。 – UncleBens 2011-02-18 19:32:12

+0

我認爲這是一個Visual C++「功能」。對其他編譯器使用'static_assert(sizeof(T)== sizeof(F),「no way」))。 – 2011-02-18 22:51:03

+0

違規當然不是一項功能。無論如何,`sizeof(T)== 0`是使斷言總是失敗的好方法,但依賴於它。 (我有一個'always_false ::價值'模板躺在。) – GManNickG 2011-02-18 23:11:27

回答

5

據我所知(我可能不完全正確的,規格是有點複雜),模板類型推導規則與你共謀。

編譯器首先嚐試替換所有的模板(它不是在這一點上選擇尚未—只是尋找選項),並得到:

  • T const &r比賽int左值與T = int,創造f(int const &)
  • T &&r匹配int左值與T = int&int & &&簡化爲int&,創建f(int &)(在spec中有規則說這個)。

現在談到選擇正確的過載和後來更好的匹配,因爲第一個不同的cv資格,後來不是。這也是爲什麼當你刪除const時,你會得到模糊的過載錯誤—,重載結果完全相同。

廣告更新1gcc支持many of the C++0x features。您可以從mingw或使用cygwin生成本機窗口。

廣告更新2:如果你真的需要對右值和右值分開重載,那似乎是唯一的選擇。但是大多數模板只是用任何一種參考來做正確的事情,或許使用std::forward來確保它們調用的函數的正確解析取決於它們是右值還是左值)。

3

雖然您的修復程序不能解決static_assert問題。 static_assert(false, ...)仍然會觸發定義時分析模板的編譯器(大部分都是這樣)。

他們會看到任何函數模板實例化都會不合格,並且標準允許它們爲模板本身發出錯誤,並且大多數都會這樣做。

爲了使這項工作您需要使表達式相關,以便編譯器不知道它何時解析模板,它總是評估爲false。例如

template<class> struct false_ { static bool const value = false; }; 

template<class T> 
T f(T &&r) 
{ 
    static_assert(false_<T>::value, "no way"); //< line # 10 
    return r; 
}