I ran into some trouble trying to implement a smart equality test macro-type template function in Visual C++ 2010 that had to do with a bug in VS in regard to default arguments of template functions. I fixed it by wrapping the value of the parameter in an extra function, but now I found that I can't use the function twice in one line!
Header file:
// 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
Source file:
// 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;
}
The error is reported as follows:
------ Build started: Project: test, Configuration: Debug Win32 ------
test.cpp
c:\users\ninja\documents\visual studio 2010\projects\test\test\test.cpp(24): error C2440: 'default argument' : cannot convert from 'const float *' to 'const float &'
Reason: cannot convert from 'const float *' to 'const float'
There is no context in which this conversion is possible
The offending line is the one where I try to call smartEqual() twice using the logical AND.
I don't understand why this happens. Changing "eps" from a reference type to a straightforward value type fixes it, but I wish I knew what was going on.
Thanks!
I think you've now hit this VS10 bug.
Your code compiles OK on VS11 Beta.
You could possibly avoid the default value (which seems to be a major issue for VS10) by changing smartEqual
to:
template<typename T> inline bool smartEqual(
const T &v1,
const T &v2)
{
return (v1 == v2);
}
and simply specialising for float (and double) like this:
template<> bool myspace::smartEqual<float>(
const float &v1,
const float &v2)
{
return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon());
}
Another option is to change the epsilon parameter to pass by value:
template<typename T> inline bool smartEqual(
const T &v1,
const T &v2,
T eps = epsilon<T>())
{
return (v1 == v2);
}
code failed in VS2010 but OK in Intel compiler. looks like a bug in VS2010
After some consideration, I've decided to go with a still another solution that @Fraser suggested (although I got the inspiration from him) and write my own answer:
Since VS seems overriden with bugs in regard to default values of parameters (only in templates?), it seems the most sensible thing to do is sidestep the issue by creating two versions of smartEqual; with and without the eps (using the default), which pretty much does the same thing, if not as concisely:
// 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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With