visual c ++ std :: isfinite()标准符合吗?

时间:2015-06-02 12:12:27

标签: c++ c++11 cmath

我有一个包装类,它有一个简单且加权轻量级的隐式转换运算符double

我喜欢使用它,因为我会使用double,例如:

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

std::isfinite(double)的visual c ++实现实际上是一个通过副本获取其参数的模板。

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

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

if (!std::isfinite((double)myVar)) ...
每次通话

如果visual c ++ std::isfinite()被定义为cppreference.com,我就不必每次调用:([编辑]我可能错了,Integral isn& #39; t实际类型......但是...... [编辑]它仍然不应该接受用户定义的类型?)

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

我不确定标准对此有何看法。 vc ++模板std::isfinite是否符合标准?

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

我应该定义自己调用isfinite(double)的{​​{1}}吗?

修改

或许这是一个非问题,因为在发布版本中调用内联并且没有复制? (好吧,我现在尝试检查并在几分钟后更新)

编辑2

在使用/ Ob2(内联任何合适的函数)的发布版本中似乎没有内联

编辑3

根据要求提供样本:

std::isfinite

编辑4

所以,根据Ben Voigt的评论,这就是我在课程标题中添加的内容:

struct DoubleWrapper {

  double value;

  DoubleWrapper(double value) : value(value) {
    printf("copy Ctor\n");
  }

  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
}

这是正确的解决方案吗?

唯一的问题是,对于所有需要加倍的#include <cmath> namespace std { inline bool isfinite(const DoubleWrapper<double> & dw) { return isfinite((double)dw); } } 函数,我应该这样做吗?

编辑5

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

如果我理解正确,而不是我的编辑4,我应该将其添加到我的班级标题中:

<cmath>

是否需要将其放在命名空间中,或者我可以将其保留在&#34; global&#34;命名空间?

但这意味着我必须将所有来电从inline bool isfinite(const DoubleWrapper<double> & dw) { return isfinite((double)dw); } using std::isfinite; 更改为std::isfinite(dw)

好的,但我发现有许多事情我不明白。 我很困惑。

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

但是,允许添加模板专业化?为什么?它有什么不同?

无论如何,我试过了,这不是我问题的解决方案,因为这个专业化:

isfinite(dw)
编译器不会在标准编译器上选择

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);
}

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

令人惊讶的是,在标准模板上选择了过载(参见编辑4)... 我开始认为一些C ++规则对我来说太微妙了:(

但是,首先,为什么地球上有cmath函数,尤其是template<> inline __nothrow bool std::isfinite(MagicTarget<double> mt) { return std::isfinite((double)mt); } 模板?

接受浮点类型的其他任何事情是什么意思?

无论如何,vc ++ std::isfinite调用std::isfinite只为float,double和long double定义。 那么......重点是什么?

我认为标准委员会通过允许cmath函数作为模板搞砸了。它们只应针对相关类型定义,或者可以将其参数作为通用引用。

那是它,对不起咆哮......

我会去(不是std)重载。 谢谢!

1 个答案:

答案 0 :(得分:3)

通过评论解决您的问题的编辑问题4,您已接近最终解决方案。

您不应将其添加到std命名空间,您应该将其添加到您自己的命名空间之一,rely on argument dependent lookup请参阅Is it a good practice to overload math functions in namespace std in c++以获取更多详细信息。

鉴于标准委员会明显希望限制仅使用算术类型调用cmath函数,依赖隐式转换并不是一个好主意。因此,通过强制转换执行显式转换是实现所有cmath函数的安全方法:

isfinite((double)dw)

您可以在Is it valid to pass non-arithmetic types as arguments to cmath functions?

中找到详细信息