在linux和windows上std :: min / max类型扣除不同

时间:2014-08-01 19:02:43

标签: c++ opencv visual-c++ gcc stl

在下面的代码中,std :: min / max的模板类型推导似乎很奇怪,我想知道为什么以及如何正确修复它。

以下适用于Windows VS2013,并在GCC-4.8上发出编译错误:(参见下面的错误)

int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0f);

这在GCC-4.8上编译,但在VS2013上给出了编译错误:(见下面的错误)

int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0);

v[1-3]cv::Vec3f v1, v2, v3;

来自OpenCV的

,cv :: Vec3f是Vec<float, 3>,而Vec的运算符[]是

const _Tp& operator [](int i) const;
_Tp& operator[](int i);

min / max / floor / ceil来自std :: namespace(即代码顶部的using std::min等)。

所以当我写

int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0f);

类型应该是

max(min(float, min(float, float), float);

那为什么海湾合作委员会会在这里纾困?

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'

GCC-4.8错误:

error: no matching function for call to 'max(const double&, float)'

答案:

GCC没有使用std :: floor而是使用全局命名空间(由cmath绘制)。如果我添加using std::floor,则所有代码都按预期工作!全局命名空间中令人讨厌的双层(...)函数!

3 个答案:

答案 0 :(得分:4)

如果在本声明中不是拼写错误

int minX = max(min(floor(v1[0]), min(floor(v2[0]), floor(v3[0]))), 0.0);

整数文字9.9的类型为double,而其他操作数的类型为float。因此,编译器无法决定是使用模板参数float还是double

错误消息说清楚功能

'const _Ty &std::max(const _Ty &,const _Ty &)' 

could be 'double' or 'float'

这就是funcrion调用看起来像

std::max( float_value, double_value );

您可以明确指定模板参数,例如

std::max<double>( float_value, double_value );

std::max<float>( float_value, double_value );

对于GCC,它将全局命名空间中返回类型为floor的标准C函数double放置..

double floor(double x);

因此应用此函数后的操作数将转换为double类型。但似乎MS VC ++没有将此函数放在全局命名空间中,或者MS VC ++中的全局命名空间没有重载具有相同名称的函数。

所以这个问题与每个编译器在全局命名空间中放置的函数floor有关。

我认为如果您使用限定名std::floor,那么GCC也会发出错误。

所以在你的代码中MS VC ++使用函数

float floor(float x);

并且结果在GCC使用函数时发出错误

double floor(double x);

并且函数std::max的所有操作数都具有类型double并且代码编译成功。:)

答案 1 :(得分:1)

所以可能让你感到困惑的是Windows平台标题中的一个可怕的黑客攻击已经存在多年了:

从内心深处“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

这很可能意味着,您的Windows版本可能正在使用#define宏而不是<algorithm>的最小/最大值。

如果您明确使用std::minstd::max,这将避免宏扩展,max<T>min<T>也是如此。我个人提到#define NOMINMAX之前要包括<windows.h>或将在我的所有项目中包含该标题的标题,以便我得到“标准”行为。例如,这是我在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>
...

请参阅知识库143208

当然,这假设有问题的模块以某种方式提取<windows.h> ......

答案 2 :(得分:0)

根据我在GCC-4.8的数学实现中的记忆,floor函数返回double。那就是问题所在。尝试显式转换为float或尝试使用您自己的floor