visual c++ std::isfinite() 是否符合标准?
Is visual c++ std::isfinite() standard conforming?
我得到了一个包装器 class,它有一个简单的 light-weighted 隐式转换运算符到 double
。
我喜欢像使用 double 一样使用它,例如:
if (!std::isfinite(myVar)) ...
但是std::isfinite(double)
的visual c++实现实际上是一个模板,通过复制得到他的参数。
所以我的包装器 class 复制构造函数被调用,它不是 light-weighted.
为了避免这种情况,我必须写:
if (!std::isfinite((double)myVar)) ...
对于每次调用 :(
如果 visual c++ std::isfinite()
的定义与 cppreference.com 上的一样,我就不必每次都调用:([edit] 我可能错了,Integral 不是实际类型...但是...[编辑]它仍然不应该接受用户定义的类型?)
bool isfinite( float arg );
bool isfinite( double arg );
bool isfinite( long double arg );
bool isfinite( Integral arg );
我不确定标准对此有何规定。
是 vc++ 模板 std::isfinite
standard-conforming ?
我应该将此报告为 Microsoft 连接上的错误吗?
我应该定义自己的 isfinite(double)
来调用 std::isfinite
吗?
编辑
或者它可能是一个 non-issue,因为在发布版本中,调用被内联并且没有发生复制? (好吧,我会尝试立即检查并在几分钟内更新)
编辑 2
它似乎没有在带有 /Ob2 的发布版本中内联(内联任何合适的函数)
编辑 3
根据要求,样品:
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
}
编辑 4
因此,根据 Ben Voigt 的评论,这就是我添加到 class header:
中的内容
#include <cmath>
namespace std {
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
}
这是正确的解决方案吗?
唯一的问题是,我是否应该对所有需要 double 的 <cmath>
函数做同样的事情?
编辑 5
我在这里回复 Shafik Yaghmour 的回答,因为评论太有限(也许我应该开始一个新问题)
如果我理解正确,而不是我的编辑 4,我应该将它添加到我的 class header:
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
using std::isfinite;
是否需要将它放在一个命名空间中,或者我可以将它留在 "global" 命名空间中吗?
但这意味着我必须将所有调用从 std::isfinite(dw)
更改为 isfinite(dw)
。
好的,但我发现有很多事情我不明白。
我很困惑。
我知道向 std 添加 overload 是不允许的。
但是,允许添加模板专业化?为什么 ?它有什么区别?
无论如何,我试过了,但它不能解决我的问题,因为这个专业化:
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 函数作为模板搞砸了。它们应该只为相关的类型定义,或者可能将它们的参数作为通用引用。
就是这样,不好意思再吐槽了...
我会去(不是在 std 中)过载。
谢谢!
解决您的问题的编辑 4,因为通过评论您已经接近最终解决方案。
您不应该将它添加到 std
命名空间,您应该将它添加到您自己的命名空间之一,rely on argument dependent lookup see Is it a good practice to overload math functions in namespace std in c++ 了解更多详细信息。
鉴于标准委员会明显希望限制 cmath
函数只能用算术类型调用,依赖隐式转换不是一个好主意。因此,通过强制转换执行显式转换是所有 cmath
函数的安全方法:
isfinite((double)dw)
您可以在 中找到详细信息。
我得到了一个包装器 class,它有一个简单的 light-weighted 隐式转换运算符到 double
。
我喜欢像使用 double 一样使用它,例如:
if (!std::isfinite(myVar)) ...
但是std::isfinite(double)
的visual c++实现实际上是一个模板,通过复制得到他的参数。
所以我的包装器 class 复制构造函数被调用,它不是 light-weighted.
为了避免这种情况,我必须写:
if (!std::isfinite((double)myVar)) ...
对于每次调用 :(
如果 visual c++ std::isfinite()
的定义与 cppreference.com 上的一样,我就不必每次都调用:([edit] 我可能错了,Integral 不是实际类型...但是...[编辑]它仍然不应该接受用户定义的类型?)
bool isfinite( float arg );
bool isfinite( double arg );
bool isfinite( long double arg );
bool isfinite( Integral arg );
我不确定标准对此有何规定。
是 vc++ 模板 std::isfinite
standard-conforming ?
我应该将此报告为 Microsoft 连接上的错误吗?
我应该定义自己的 isfinite(double)
来调用 std::isfinite
吗?
编辑
或者它可能是一个 non-issue,因为在发布版本中,调用被内联并且没有发生复制? (好吧,我会尝试立即检查并在几分钟内更新)
编辑 2
它似乎没有在带有 /Ob2 的发布版本中内联(内联任何合适的函数)
编辑 3
根据要求,样品:
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
}
编辑 4
因此,根据 Ben Voigt 的评论,这就是我添加到 class header:
中的内容#include <cmath>
namespace std {
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
}
这是正确的解决方案吗?
唯一的问题是,我是否应该对所有需要 double 的 <cmath>
函数做同样的事情?
编辑 5
我在这里回复 Shafik Yaghmour 的回答,因为评论太有限(也许我应该开始一个新问题)
如果我理解正确,而不是我的编辑 4,我应该将它添加到我的 class header:
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
using std::isfinite;
是否需要将它放在一个命名空间中,或者我可以将它留在 "global" 命名空间中吗?
但这意味着我必须将所有调用从 std::isfinite(dw)
更改为 isfinite(dw)
。
好的,但我发现有很多事情我不明白。 我很困惑。
我知道向 std 添加 overload 是不允许的。
但是,允许添加模板专业化?为什么 ?它有什么区别?
无论如何,我试过了,但它不能解决我的问题,因为这个专业化:
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 函数作为模板搞砸了。它们应该只为相关的类型定义,或者可能将它们的参数作为通用引用。
就是这样,不好意思再吐槽了...
我会去(不是在 std 中)过载。 谢谢!
解决您的问题的编辑 4,因为通过评论您已经接近最终解决方案。
您不应该将它添加到 std
命名空间,您应该将它添加到您自己的命名空间之一,rely on argument dependent lookup see Is it a good practice to overload math functions in namespace std in c++ 了解更多详细信息。
鉴于标准委员会明显希望限制 cmath
函数只能用算术类型调用,依赖隐式转换不是一个好主意。因此,通过强制转换执行显式转换是所有 cmath
函数的安全方法:
isfinite((double)dw)
您可以在