2012-10-16 13 views
7

Ecco il mio codice C++ (sto usando Visual C++ 2010):come posso evitare l'errore del compilatore: std :: transform?

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

quando ho rimuovere il commento la riga:

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

ho ricevuto il messaggio di errore:

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

ma, la riga di codice:

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

può funzionare. In realtà, quello che uso è la stessa funzione: abs, sono confuso sul risultato. Inoltre, vorrei sapere se è possibile unire le seguenti due righe di codice in uno (che è una std::transform chiamata, con lo stesso effetto):

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

Qualcuno mi può aiutare sui due domande?

+7

Le funzioni di overload non funzionano bene con l'uso come puntatori di funzione in contesti generici. La soluzione più semplice visto che stai usando VS2010: usa un lambda. 'std :: transform (vec.begin(), vec.end(), vec.begin(), [&] (int i) {return abs (dpi-i); }); ' – Xeo

risposta

7

Il problema è che std::abs ha several overloads. Ecco perché il compilatore non riesce a capire quale sovraccarico si sta tentando di utilizzare nella chiamata di funzione std::transform.

Al fine di risolvere il problema, si potrebbe fare quello che @Xeo menzionato nel suo commento:

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

Oppure si potrebbe lanciare statici per ottenere l'indirizzo della funzione appropriata:

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

quanto riguarda la tua ultima domanda, sì, lambda funzionano come un fascino qui:

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

sei fantastico, puoi dirmi la soluzione alla seconda domanda: voglio sapere se è possibile unire le seguenti due righe di codice in una (cioè una chiamata std :: transform, con la stessa effetto): std :: transform (vec.begin(), vec.end(), vec.begin(), std :: bind1st (std :: minus (), dpi)); std :: transform (vec.begin(), vec.end(), vec.begin(), absd); – Triumphant

+0

@Triumphant sicuro, ecco qua. – mfontanini

2

abs è un sovraccarico funzione ed, non una singola entità, quindi la chiamata a std::transform non può dedurre l'argomento modello perché non esiste una singola funzione a cui si fa riferimento con il nome abs.

È equivalente a questo:

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

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

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

Si può dire al compilatore che abs si intende per la conversione in modo esplicito al tipo di funzione che si intende:

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

o creando un variabile che si riferisce alla funzione desiderata:

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

A co mbine le due trasformazioni in una puoi usare una lambda, come suggerisce Xeo, oppure usa std::bind ad es.

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

Oppure per C++ 03 è possibile utilizzare boost::bind.

+0

Risposta meravigliosa. Che ne dici della seconda domanda: voglio sapere se è possibile unire le seguenti due righe di codice in una (ovvero una chiamata std :: transform, con lo stesso effetto): std :: transform (vec.begin (), vec.end(), vec.begin(), std :: bind1st (std :: minus (), dpi)); std :: transform (vec.begin(), vec.end(), vec.begin(), absd); – Triumphant

+0

Come ho detto, vedere il commento di Xeo, o ho modificato la risposta per mostrare come farlo con 'bind' –

+0

ciao, ho ottenuto errore di compilazione con: usando std :: segnaposti :: _ 1; int (* p) (int) = abs; std :: transform (vec.begin(), vec.end(), vec.begin(), std :: bind (p, std :: bind (std :: minus (), dpi, _1))); error messenge: 1> D: \ ProgramFiles \ VS 2010 \ VC \ include \ xxcallfun (7): errore C2664: 'int (int)': impossibile convertire il parametro 1 da 'std :: tr1 :: _ Bind_fty <_Fty , _Ret, _BindN> 'a' int ' – Triumphant

Problemi correlati