2012-04-27 42 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); 
相关问题