我想编写一个通用的abs
函数,它可以正确地适用于每种类型。基本上,我想使用以下算法:
std::abs
from <cstdlib>
.std::abs
from <cmath>.
。abs
的用户定义类型,请使用它。abs
算法。以下是我想出的:
#include <cmath>
#include <cstdlib>
namespace math
{
namespace detail
{
// generic abs algorithm
template<typename T>
constexpr auto abs(const T& value)
-> T
{
return (T{} < value) ? value : -value;
}
}
template<typename T>
constexpr auto abs(const T& value)
-> T
{
using std::abs;
using detail::abs;
return abs(value);
}
}
其思想是创建一个通用的detail::abs
算法,然后创建另一个abs
函数,该函数将通过依赖于参数的查找来选择要调用的函数。以下是我试图考虑的问题:
std::abs
可能会为这些类型生成优化的代码。如果可能的话,使用std::abs
可能会生成一个优化的可执行文件。也就是说,std::abs
缺乏constexpr
,这是一个理想的特性,编译器可能会识别出一个类似于绝对值的构造,并对其进行优化.abs
,它的行为与泛型算法不同。因此,如果这个命名空间级函数存在,我们必须调用它。const&
的参数,因为某些命名空间级别的abs
也可以通过const&
接受它们的参数。operator<
来表示排序,而不提供其他关系运算符。因此,在泛型算法中调用operator<
的可能性更大。T{}
而不是0
进行比较,以便能够表示任何给定类型的默认值。类型不能保证可与整数相比较。下面是一个测试用例来演示该函数可以实现什么(您也可以测试它在线):
命名空间鸡蛋{ struct { Foo(int val):val(val) {} int val;};Foo abs(Foo foo) { eggs { std::abs(foo.val) };} struct { Bar(int val=0):val(val) {} Bar运算符-() const { -val };} int val;};bool operator<(const & lhs,const & rhs) {返回lhs.val < rhs.val;} int (){使用std::lhs.val;cout <<数学::abs(-5) << '\n';std:cout <<数学::abs(-5.3f) << '\n';std::cout <<数学:abs(-5i+2.0) << '\n';鸡蛋: foo foo={ -8 };std::cout <<数学:abs(Foo).val << '\n';bar ={ -9 };cout <<数学::abs(Bar).val <<‘n’;}
你觉得这样的功能怎么样?我错过了什么模糊的错误吗?您看到什么可以改进的地方了吗(在实现中,我不关心测试用例)?
发布于 2014-08-15 07:38:37
我相信您的泛型实现中有一个bug,特别是在有符号-零值的浮点样式类方面:
你的代码:
return (T{} < value) ? value : -value;
最好是作为一个T{} <= value
(或重写为(T{} > value) ? -value : value;
)。
当前逻辑将返回输入值-0.0
的0.0
,这不适合于abs()
函数。
此外,我不知道您将如何真正测试这些东西,因为,如果我没有弄错,在浮点比较与符号零值,-0.0 == 0.0
,但我希望abs(-0.0)
会返回0.0
。
不过,我不知道你是怎么解决这个问题的。
发布于 2014-08-15 07:17:44
我只想说明一下如何使用boost::call_traits
(参见这里 )。这将选择传递参数的“最佳”方式,而不是总是通过const T&
传递:小的const T
,内置的类型(如int
),类类型的const T&
。
template<typename T>
constexpr auto abs(boost::call_traits<T>::param_type value)
-> T
{ ... }
https://codereview.stackexchange.com/questions/60140
复制相似问题