是否符合visual c++std::isfinite()标准

Is visual c++ std::isfinite() standard conforming?

本文关键字:isfinite 标准 c++std visual 是否      更新时间:2023-10-16

我得到了一个包装类,它有一个到double的简单而轻量级的隐式转换运算符。

我喜欢使用它,就像我会使用替身一样,例如:

if (!std::isfinite(myVar)) ...

std::isfinite(double)的可视化c++实现实际上是一个通过复制获得其论点的模板。

所以我的包装类复制构造函数被调用了,而且它不是轻量级的。

为了避免这种情况,我必须写:

if (!std::isfinite((double)myVar)) ...

对于每个呼叫:(

如果可视化c++std::isfinite()是在cppreference.com上定义的,我就不必强制执行每个调用:([edit]我可能错了,Integral不是一个实际的类型…但是…[edit>它仍然不应该接受用户定义的类型?(

bool isfinite( float arg );
bool isfinite( double arg );
bool isfinite( long double arg );
bool isfinite( Integral arg );

我不确定这个标准是怎么说的。vc++模板std::isfinite是否符合标准?

我应该将此报告为Microsoft connect上的错误吗?

我应该定义我自己的isfinite(double),调用std::isfinite吗?

编辑

或者,这可能不是问题,因为在发布版本中,调用被内联,并且没有发生复制?(好吧,我现在就试着检查一下,几分钟后更新(

编辑2

在使用/Ob2(内联任何合适的函数(的版本构建中,它似乎没有内联

编辑3

根据要求,提供样品:

struct DoubleWrapper {
  double value;
  DoubleWrapper(double value) : value(value) {
    printf("copy Ctorn");
  }
  DoubleWrapper(const DoubleWrapper & that) : value(that.value) {}
  operator double() const {
    return this->value;
  }
};
int main() {
  DoubleWrapper a(rand());      //rand to prevent optimization
  auto res = std::isfinite(a);
  printf("%d", res);            //printf to prevent optimization
}

编辑4

因此,根据Ben Voigt的评论,这是我在类标题中添加的内容:

#include <cmath>
namespace std {
    inline bool isfinite(const DoubleWrapper<double> & dw) {
        return isfinite((double)dw);
    }
}

这是一个正确的解决方案吗?

唯一的问题是,我是否应该对所有使用双精度的<cmath>函数执行相同的操作?

编辑5

我在这里回应Shafik Yaghmour的回答,因为评论太有限了(也许我应该开始一个新的问题(

如果我理解正确,我应该把它添加到我的类标题中,而不是编辑4:

inline bool isfinite(const DoubleWrapper<double> & dw) {
    return isfinite((double)dw);
}
using std::isfinite;

是否需要将其放在命名空间中,或者我可以将其保留在"全局"命名空间中?

但这意味着我必须将所有呼叫从std::isfinite(dw)更改为isfinite(dw)

好吧,但我意识到有很多事情我不明白。我很困惑。

我知道在std中添加重载是不允许的。

但是,是否允许添加模板专用化?为什么?这有什么区别?

不管怎样,我试过了,但这并不能解决我的问题,因为这种专业化:

template<> inline __nothrow bool std::isfinite(const MagicTarget<double> & mt) {
    return std::isfinite((double)mt);
}

编译器不会选择标准的

template<class _Ty> inline __nothrow bool isfinite(_Ty _X)
{
    return (fpclassify(_X) <= 0);
}

要选择,它应该是

template<> inline __nothrow bool std::isfinite(MagicTarget<double> mt) {
    return std::isfinite((double)mt);
}

但这仍然会将副本称为Ctor:(

令人惊讶的是,重载(见编辑4(是在标准模板上选择的。。。我开始觉得有些C++规则对我来说太微妙了:(

但是,首先,为什么cmath函数,尤其是std::isfinite是一个模板?

接受浮点类型的其他东西有什么意义?

无论如何,vc++std::isfinite调用仅为float、double和long double定义的std::fpclassify。那么…这有什么意义?

我认为标准委员会把cmath函数作为模板搞砸了。它们应该只为相关的类型定义,或者可能将它们的参数作为通用引用。

就这样,对不起你的咆哮。。。

我会选择(非标准(过载。非常感谢。

通过这些评论,您已经接近最终解决方案,因此,对您的问题进行编辑4。

您不应该将其添加到std命名空间,而应该将它添加到您自己的命名空间中,并依赖于参数相关的查找。有关更多详细信息,请参阅在c++中的命名空间std中重载数学函数是否是一种好的做法。

考虑到标准委员会显然希望限制cmath函数只能用算术类型调用,依赖隐式转换不是一个好主意。因此,通过强制转换执行显式转换是所有cmath函数的安全方法:

isfinite((double)dw)

您可以在将非算术类型作为参数传递给cmath函数有效吗?中找到详细信息?。