How can I avoid a compiler error: std :: transform?

Here is my C ++ code (I am using Visual C ++ 2010):

int absd(int t) { return abs(t); } int main() { try { int dpi = 137; int dpiCriterionAry[] = {100, 150, 200, 300, 400, 500, 600}; std::vector<int> vec(dpiCriterionAry, dpiCriterionAry + _countof(dpiCriterionAry)); std::transform(vec.begin(), vec.end(), vec.begin(), std::bind1st(std::minus<int>(), dpi)); std::transform(vec.begin(), vec.end(), vec.begin(), absd); //std::transform(vec.begin(), vec.end(), vec.begin(), abs); copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, "\t")); cout << endl; } catch(exception& e) { cerr << e.what() << endl; } return 0; } 

when I uncomment the line:

 //std::transform(vec.begin(), vec.end(), vec.begin(), abs); 

I got an error message:

 1>------ Build started: Project: Console, Configuration: Release Win32 ------ 1>Build started 2012/10/16 21:17:19. 1>InitializeBuildStatus: 1> Creating "..\Intermediate\Console.unsuccessfulbuild" because "AlwaysCreate" was specified. 1>ClCompile: 1> Console.cpp 1>Console.cpp(16): error C2780: '_OutIt std::transform(_InIt1,_InIt1,_InIt2,_OutIt,_Fn2)' : expects 5 arguments - 4 provided 1> D:\ProgramFiles\VS 2010\VC\include\algorithm(1155) : see declaration of 'std::transform' 1>Console.cpp(16): error C2914: 'std::transform' : cannot deduce template argument as function argument is ambiguous 1>Console.cpp(16): error C2914: 'std::transform' : cannot deduce template argument as function argument is ambiguous 1>Console.cpp(16): error C2784: '_OutIt std::transform(_InIt,_InIt,_OutIt,_Fn1)' : could not deduce template argument for '_OutIt' from 'std::_Vector_iterator<_Myvec>' 1> with 1> [ 1> _Myvec=std::_Vector_val<int,std::allocator<int>> 1> ] 1> D:\ProgramFiles\VS 2010\VC\include\algorithm(1051) : see declaration of 'std::transform' 1> 1>Build FAILED. 1> 1>Time Elapsed 00:00:02.48 ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

but a line of code:

 std::transform(vec.begin(), vec.end(), vec.begin(), absd); 

can work. In fact, I use the same function: abs , I am confused by the result. In addition, I want to know whether it is possible to combine the following two lines of code into one (this is one call to std::transform with the same effect):

 std::transform(vec.begin(), vec.end(), vec.begin(), std::bind1st(std::minus<int>(), dpi)); std::transform(vec.begin(), vec.end(), vec.begin(), absd); 

Can anyone help me with two questions?

+7
source share
2 answers

The problem is that std::abs has several overloads . Therefore, the compiler cannot determine which overload you are trying to use when calling the std::transform function.

To fix this, you could do what @Xeo mentioned in his comment:

 std::transform(vec.begin(), vec.end(), vec.begin(), [&](int i){ return abs(i); }); 

Or you can use a static cast to get the corresponding function address:

 std::transform(vec.begin(), vec.end(), vec.begin(), static_cast<int(*)(int)>(abs)); 

As for your last question, yes, lambdas work like a charm here:

 std::transform(vec.begin(), vec.end(), vec.begin(), [&](int i) { return absd(dpi - i); } ); 
+7
source

abs is an overloaded function, not a single entity, so calling std::transform cannot output a template argument because there is not a single function called abs .

This is equivalent to this:

 void foo(int) { } void foo(const char*) { } template<typename T> int bar(T) { return 0; } int i = bar(foo); // which 'foo' ? 

You can tell the compiler that abs means that it explicitly converts it to the type of function that you mean:

 std::transform(vec.begin(), vec.end(), vec.begin(), (int (*)(int))abs); 

Or by creating a variable, referring to the desired function:

 int (*p)(int) = abs; std::transform(vec.begin(), vec.end(), vec.begin(), p); 

To combine the two conversions into one, you can use lambda, as Xeo suggests, or use std::bind for example.

 using std::placeholders::_1; int (*p)(int) = abs; std::transform(vec.begin(), vec.end(), vec.begin(), std::bind(p, std::bind(std::minus<int>(), dpi, _1))); 

Or for C ++ 03 you can use boost::bind instead.

+2
source

All Articles