std::abs 与 std::transform 不起作用

Mat*_*att 4 c++ stl

拿这个例子:

#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>

void PrintVec(const std::vector<float>&);
int main(int argc, char * argv[]){

float vals[] = {-1.2,0.0,1.2};
std::vector<float> test(vals, vals + sizeof(vals) / sizeof(float));
std::vector<float> absTest(3);

std::transform(test.begin(), test.end(), absTest.begin(), std::abs<float>());

PrintVec(test);
PrintVec(absTest);

return 0;
}

void PrintVec(const std::vector<float> &vec){
for (unsigned int i = 0; i < vec.size(); ++i){
    std::cout << vec[i] << '\n';
}
return;
}
Run Code Online (Sandbox Code Playgroud)

使用 gcc 4.3.4 和 VS 2013 我得到编译器错误。对于 gcc 来说:

testTransformAbs.cpp:15: 错误:'float' 之前的预期主表达式

对于 VS 2013,其:

错误 C2062: 意外键入“float”

如果我删除<float>然后我得到这个错误:

testTransformAbs.cpp:15: 错误: 没有匹配的函数调用 'abs()' /usr/include/stdlib.h:766: 注意:候选对象是:int abs(int) /usr/include/c++/4.3/cstdlib :144: 注意: long int std::abs(long int) /usr/include/c++/4.3/cstdlib:175: 注意: long long int __gnu_cxx::abs(long long int) /usr/include/c++/4.3 /cmath:99:注意:double std::abs(double) /usr/include/c++/4.3/cmath:103:注意:float std::abs(float) /usr/include/c++/4.3/cmath:107 :注意:long double std::abs(long double)

我可以创建自己的函数

float MyAbs(float f){
    return sqrt(f * f);
}

std::transform(test.begin(), test.end(), absTest.begin(), MyAbs);
Run Code Online (Sandbox Code Playgroud)

一切正常。cplusplus.com 上的参考说第四个输入可以是由以下定义的 UnaryOperation:

接受 InputIterator 指向的类型的一个元素作为参数的一元函数,并返回一些可转换为 OutputIterator 指向的类型的结果值。这可以是函数指针或函数对象。

对我来说,这应该可以使用std::abs(). 我也尝试fabs过同样的结果。我错过了什么?

int*_*jay 6

std::abs是重载函数,而不是模板函数。当获得一个指向函数的指针时,你可以通过强制转换来选择一个特定的重载:

std::transform(test.begin(), test.end(), absTest.begin(),
    static_cast<float (*)(float)>(&std::abs));
Run Code Online (Sandbox Code Playgroud)

或使用函数指针变量:

float (*fabs)(float) = &std::abs;
std::transform(test.begin(), test.end(), absTest.begin(), fabs);
Run Code Online (Sandbox Code Playgroud)

请注意,我还删除了()您放在 之后的abs,因为这是一个函数而不是需要实例化的类。


sme*_*lin 5

std::abs不是模板。标头中以 ac 为前缀的任何函数(如模板)cmathcstdlib不具有任何 C++ 功能(如模板),因为它们代表 C 标准库。也std::abs适用于整数类型。您应该使用std::fabs作为浮点类型。

我不喜欢函数指针强制转换,因此在这种情况下,我通常会编写一些如下的包装器:

namespace hlp {
template <class T> struct iabs { 
    static_assert(std::is_integral<T>::value, "");
    T operator()(T const& t){ return std::abs(t); } 
};
template <class T> struct fabs { 
    static_assert(std::is_floating_point<T>::value, ""); 
    T operator()(T const& t){ return std::fabs(t); } 
};
}
Run Code Online (Sandbox Code Playgroud)

您可以像在问题中使用 std::abs 一样使用这些包装器。当您尝试对浮点类型使用整型版本时,将会static_assert生成一个干净的编译器错误,反之亦然。