In the following code, the template type deduction for std::min/max seems to be weird and I'd like to know why and how to properly fix it.
The following works on Windows VS2013, and gives a compile-error on GCC-4.8: (see below for the error)
int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0f);
And this compiles on GCC-4.8 but gives a compile-error on VS2013: (see below for the error)
int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0);
v[1-3]
are a cv::Vec3f v1, v2, v3;
from OpenCV, a cv::Vec3f is a Vec<float, 3>
and Vec
's operator[] is
const _Tp& operator [](int i) const;
_Tp& operator[](int i);
The min/max/floor/ceil are from the std:: namespace (i.e. using std::min
etc. at the top of the code).
So when I write
int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0f);
the types should be
max(min(float, min(float, float), float);
So why does GCC bail out here?
Error on VS2013:
error C2782: 'const _Ty &std::max(const _Ty &,const _Ty &)' : template parameter '_Ty' is ambiguous
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(4086) : see declaration of 'std::max'
could be 'double' or 'float'
Error on GCC-4.8:
error: no matching function for call to 'max(const double&, float)'
Answer:
GCC wasn't using std::floor but floor from the global namespace (drawn in by cmath). If I add using std::floor
, all the code works as expected! Nasty double floor(...) function in the global namespace!
If it is not a typo then in this statement
int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0);
integer literal 9.9
has type double
while other operands have type float. So the compiler can not decide whether to use template argument float
or double
The error message says clear that for function
'const _Ty &std::max(const _Ty &,const _Ty &)'
there could be 'double' or 'float'
That is the funcrion call looks as
std::max( float_value, double_value );
You could explicitly specify the template argument as for example
std::max<double>( float_value, double_value );
or
std::max<float>( float_value, double_value );
As for GCC then it places the standard C function floor
that has return type double
in the global namespace..
double floor(double x);
So the operands after applying this function are converted to the type double. But it seems that MS VC++ does not places this function in the global namespace or the global namespace in MS VC++ has overloaded functions with the same name.
So the problem is relative to what function(s) floor
each compiler places in the global namespace.
I think that if you used qualified name std::floor
then GCC would also issue an error.
So in your code MS VC++ uses function
float floor(float x);
and as the result issues the error while GCC uses function
double floor(double x);
and all operands of function std::max
have type double
and the code is compiled successfully.:)
So the thing that is probably confusing you is a terrible hack in the Windows platform headers that has been there for ages:
From deep inside "ntdef.h"
#ifndef NOMINMAX
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#endif // NOMINMAX
That means in all likelihood, your Windows build is probably using the #define macro and not <algorithm>
's min/max as you think it is.
If you use std::min
or std::max
explicitly, this will avoid the macro expansion, as would max<T>
and min<T>
. Personally I make a point of doing #define NOMINMAX
before including <windows.h>
or headers that are going to include that header in all my projects so I get "standard" behavior. For example, a this is the Precompiled Header I use in DirectX Tool Kit:
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <algorithm>
...
See KB 143208
Of course, this assumes that the module in question has pulled <windows.h>
in somehow...
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