Как я могу избежать ошибки компилятора: std :: transform?

Вот мой код C ++ (я использую 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;
}

когда я раскомментирую строку:

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

Я получил сообщение об ошибке:

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 ==========

но строка кода:

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

может работать. На самом деле, я использую ту же функцию: absЯ запутался в результате.
Кроме того, я хочу знать, возможно ли объединить следующие две строки кода в одну (то есть одну std::transform звоните, с тем же эффектом):

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

Кто-нибудь может помочь мне с этими двумя вопросами?

7

Решение

Проблема в том, что std::abs имеет несколько перегрузок. Вот почему компилятор не может понять, какую перегрузку вы пытаетесь использовать в std::transform вызов функции.

Чтобы это исправить, вы можете сделать то, что @Xeo упомянул в своем комментарии:

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

Или вы можете использовать статическое приведение, чтобы получить соответствующий адрес функции:

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

Что касается вашего последнего вопроса, да, лямбды здесь работают как шарм:

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

Другие решения

abs перегруженная функция, а не единое целое, поэтому вызов std::transform не может вывести аргумент шаблона, потому что нет ни одной функции, на которую ссылается имя abs,

Это эквивалентно этому:

void foo(int) { }
void foo(const char*) { }

template<typename T>
int bar(T)
{ return 0; }

int i = bar(foo);  // which 'foo' ?

Вы можете сказать компилятору, который abs Вы имеете в виду, явно преобразовав его в тип функции, которую вы имеете в виду:

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

Или путем создания переменной, ссылающейся на функцию, которую вы хотите:

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

Чтобы объединить два преобразования в одно, вы можете использовать лямбду, как предлагает Xeo, или использовать std::bind например

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)));

Или для C ++ 03 вы можете использовать boost::bind вместо.

2

По вопросам рекламы [email protected]