2012-04-27 43 views
15

我遇到了一些麻煩,試圖在Visual C++ 2010中實現一個智能相等測試宏類型模板函數,該函數與bug in VS in regard to default arguments of template functions有關。我通過在額外的函數中包含參數的值來修復它,但是現在我發現我不能在一行中使用兩次函數!爲什麼在一行中使用這個C++函數兩次會導致編譯錯誤?

頭文件

// example.h 
#pragma once 

#include <limits> 

namespace myspace 
{ 

// Need to define this separately to avoid a Visual Studio bug 
template<typename T> T epsilon() { return std::numeric_limits<T>::epsilon(); } 

// A generic equality test 
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    const T &eps = epsilon<T>()) 
{ 
    return (v1 == v2); 
} 

// Template specialization for floating-point numbers 
template<> bool smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps); 

} // namespace myspace 

源文件:

// example.cpp 
#include "example.h" 

using namespace std; 
using namespace myspace; 

// equal-macro specialization for floats using epsilon 
template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps) 
{ 
    return (fabs(v1 - v2) < eps); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    float a,b; 
    bool x = smartEqual(a,b); // works ok 
    bool x = smartEqual(a,b) && smartEqual(b,a); // error 
    return 0; 
} 

如下報告錯誤:

------構建開始:項目:測試,配置:調試Win32 ------
test.cpp
c: (24):錯誤C2440:'默認參數':無法從'const float *'轉換爲'const float &'
原因是:\ n \ n \ ninja \不能從「常量浮動*」轉換爲「const的浮動」
沒有上下文中,這種轉換是可能

的違規行是一個,我嘗試使用兩倍的邏輯,並呼籲smartEqual() 。

我不明白爲什麼會發生這種情況。將「eps」從引用類型更改爲簡單的值類型可以修復它,但我希望我知道發生了什麼。

謝謝!

+0

如果實例'smartEqual <>()'2次,2種_different_類型,不會它會給你帶有2個版本的'epsilon()',它們僅在返回類型上有所不同? – 2012-04-27 02:25:50

+0

@Pavel:這確實也是一個有趣的問題,但是因爲int ei = epsilon (); float ef = epsilon ();編譯好吧,看起來他們在某種程度上是獨立的功能。我的意思是,編譯器以某種方式區分它們。不知道如何。 – neuviemeporte 2012-04-27 02:32:59

回答

13

我想你現在已經擊中了this VS10 bug

您的代碼在VS11測試版上編譯OK。

你可能避免的默認值(這似乎是爲VS10的一個重大問題)通過改變smartEqual到:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2) 
{ 
    return (v1 == v2); 
} 

,只是專門用於浮點(雙)這樣的:

template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2) 
{ 
    return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon()); 
} 


另一種選擇是改變的ε參數由值來傳遞:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    T eps = epsilon<T>()) 
{ 
    return (v1 == v2); 
} 
+1

抱住我,我着火了!我不寒而慄,想到在這一天完成之前我可能會解開其他哪些錯誤。 ;) – neuviemeporte 2012-04-27 02:06:01

+0

@neuviemeporte MS應該聘請你測試VS,然後釋放它。 – 2012-04-27 02:16:37

+0

@neuviemeporte,不要忘了這個小寶石:'template class A {class B:public C; };' – 2012-04-27 02:18:30

2

代碼在VS2010中失敗,但在英特爾編譯器中正常。看起來像在VS2010

2

經過一番考慮的一個錯誤,我決定用另一種解決方案,@Fraser建議(雖然我從他的靈感),去寫我自己的答案:

  1. 第一種解決方案使我可以靈活地使用eps的自定義值。
  2. 第二個解決方案的傳值感覺不對,特別是如果將來我會決定使用這個函數來處理更多的人爲操作。

由於VS似乎被參數的默認值(僅在模板中)的bugs覆蓋,似乎最明智的做法是通過創建兩個版本的smartEqual來避開問題;使用和不使用EPS(使用默認值),這幾乎做同樣的事情,如果不是因爲簡潔:

// An equality test that doesn't require the value of eps, default will be used 
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2) 
{ 
    return (v1 == v2); 
} 

// Float specialization: return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon()); 
template<> inline bool smartEqual<float>(
    const float &v1, 
    const float &v2); 

// A custom-eps value equality test 
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    const T &eps) 
{ 
    return (v1 == v2); 
} 

// Float specialization: return (fabs(v1 - v2) < eps); 
template<> bool smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps); 
相關問題