std::min/max类型扣除在Linux和Windows上不同

std::min/max type deduction different on linux and windows

本文关键字:Linux Windows min max 类型 std      更新时间:2023-10-16

在下面的代码中,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:: 命名空间(即 代码顶部的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.0VCincludealgorithm(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,而是使用全局命名空间中的 floor(由 cmath 绘制(。如果我添加using std::floor,所有代码都按预期工作!全局命名空间中讨厌的双层地板(...(函数!

如果它不是拼写错误,那么在此语句中

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

整数文本9.9具有类型 double,而其他操作数具有浮点类型。因此编译器无法决定是使用模板参数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,它将返回类型为double的标准C函数floor放在全局命名空间中。

double floor(double x);

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

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

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

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

float floor(float x);

结果在GCC使用功能时发出错误

double floor(double x);

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

因此,可能让您感到困惑的是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> 一样。就我个人而言,在包含将在我的所有项目中包含该标题的<windows.h>或标题之前,我会做#define NOMINMAX,这样我就会得到"标准"行为。例如,这是我在 DirectX 工具包中使用的预编译标头:

#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>......

根据我记得在GCC-4.8的数学实现中,floor函数返回double。这就是问题所在。尝试显式投射到浮点数或尝试使用您自己的floor