Here is my C++ code (I'm 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 the 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, the line of code:
std::transform(vec.begin(), vec.end(), vec.begin(), absd);
can work. In fact, what I use is the same function: abs
, I'm confused about the result.
Besides, I want to know if it's possible to merge the following two lines of code into one(that is one std::transform
call, 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);
Anyone can help me about the two questions?
The problem is that std::abs
has several overloads. That's why the compiler can't figure out which overload you are trying to use in the std::transform
function call.
In order to fix it, you could do what @Xeo mentioned in his comment:
std::transform(vec.begin(), vec.end(), vec.begin(), [&](int i){ return abs(i); });
Or you could static cast to get the appropriate function address:
std::transform(vec.begin(), vec.end(), vec.begin(), static_cast<int(*)(int)>(abs));
Regarding your last question, yes, lambdas work as a charm here:
std::transform(vec.begin(), vec.end(), vec.begin(), [&](int i) { return absd(dpi - i); } );
abs
is an overloaded function, not a single entity, so the call to std::transform
cannot deduce the template argument because there is not a single function referred to by the name abs
.
It 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 which abs
you mean by explicitly converting it to the type of the function you mean:
std::transform(vec.begin(), vec.end(), vec.begin(), (int (*)(int))abs);
Or by creating a variable referring to the function you want:
int (*p)(int) = abs;
std::transform(vec.begin(), vec.end(), vec.begin(), p);
To combine the two transformations into one you could use a lambda, as Xeo suggests, or use std::bind
e.g.
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 could use boost::bind
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With