std :: abs with std :: transform not working

时间:2016-02-25 21:35:21

标签: 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;
}

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

  

testTransformAbs.cpp:15:错误:在&#39; float&#39;

之前预期的primary-expression

对于VS 2013:

  

错误C2062:键入&#39; float&#39;意想不到

如果我删除<float>,则会收到此错误:

  

testTransformAbs.cpp:15:错误:没有匹配函数来调用&#39; abs()&#39;   /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);

一切正常。 cplusplus.com上的引用表示第四个输入可以是由以下内容定义的UnaryOperation:

  

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

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

2 个答案:

答案 0 :(得分:3)

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

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

或使用函数指针变量:

float (*fabs)(float) = &std::abs;
std::transform(test.begin(), test.end(), absTest.begin(), fabs);

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

答案 1 :(得分:3)

std::abs is not a template。前缀为c 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); } 
};
}

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