2011-12-12 33 views
5

Ho il seguente programma che utilizza ptr_fun con una funzione lambda.ptr_fun con una funzione lambda

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <string> 
#include <cstring> 

using namespace std; 
int main() 
{ 
    string target="aa"; 
    vector<string> v1; 
    v1.push_back("aa"); 
    v1.push_back("bb"); 
    auto stringcasecmp=[](string lhs, string rhs)->int 
    { 
     return strcasecmp(lhs.c_str(), rhs.c_str()); 
    }; 

    auto pos = find_if(
     v1.begin(), v1.end(), 
     not1(bind2nd(ptr_fun(stringcasecmp), target)) 
     ); 

    if (pos != v1.end()) 
    cout << "The search for `" << target << "' was successful.\n" 
     "The next string is: `" << pos[1] << "'.\n"; 
} 

Ottengo i seguenti messaggi di errore.

stackoverflow.cpp: In function ‘int main()’: 
stackoverflow.cpp:21:41: error: no matching function for call to ‘ptr_fun(main()::<lambda(std::string, std::string)>&)’ 
stackoverflow.cpp:22:6: error: unable to deduce ‘auto’ from ‘<expression error>’ 

Come si modifica il codice (in minima parte) per renderlo compilato?

+1

Solo un po 'sidenote: Se state pensando di usare un lambda come quello che avete qui un sacco, si potrebbe considera di passare gli argomenti come riferimento. Salva molte copie di stringhe. –

+0

Potresti scoprire che il tuo lambda 'stringcasecmp' è ricorsivo! – quamrana

+0

@quamrana Perché è ricorsivo? – ggg

risposta

9

bind2nd (§D.9) e ptr_fun (§D.8.2.1) sono deprecati in C++ 11. Si potrebbe semplicemente scrivere un'altra funzione lambda in find_if:

auto pos = find_if(v1.begin(), v1.end(), 
        [&](const std::string& s) { 
         return !stringcasecmp(s, target); 
        }); 

ptr_fun(<lambda>) non funzionerà, perché ptr_fun è progettato per C++ 03 per convertire un puntatore a funzione per un oggetto funzione per altri adattatori. Un lambda è già un oggetto funzione, quindi lo ptr_fun non è necessario.

bind2nd aspetta l'oggetto funzione per definire i membri second_argument_type e result_type, che non è vero per una lambda, in modo da scrivere bind2nd(<lambda>, target) non funzionerà neanche. Ma in C++ 11 v'è una sostituzione generica che funziona:

std::bind(stringcasecmp, std::placeholders::_1, target) 

Tuttavia, bind non restituisce un oggetto funzione 03 in stile C++, che not1 si aspetta: richiede il tipo di risultato di bind per definire il membro argument_type che non esiste. Pertanto l'espressione finale

std::not1(std::bind(stringcasecmp, std::placeholders::_1, target)) 

sarà non lavoro. La soluzione più semplice è usare un altro lambda che ho scritto sopra.

In alternativa, è possibile definire un negatore generico:

template <typename Predicate> 
struct generic_negate 
{ 
    explicit generic_negate(Predicate pred) : _pred(pred) {} 

    template <typename... Args> 
    bool operator()(Args&&... args) 
    { 
     return !_pred(std::forward<Args>(args)...); 
    } 
private: 
    Predicate _pred; 
}; 

template <class Predicate> 
generic_negate<Predicate> not_(Predicate pred) 
{ 
    return generic_negate<Predicate>(pred); 
} 

.... 

auto pos = find_if(v1.begin(), v1.end(), not_(bind(stringcasecmp, _1, target))); 

Esempio: http://ideone.com/6dktf

+0

Grazie. Penso che sia piuttosto strano che bind2nd sia deprecato, ma il bind di C++ 11 non funziona con not1. – ggg

+0

"*' ptr_fun () 'non funzionerà, perché' ptr_fun' è progettato per C++ 03 per convertire un puntatore a funzione in un oggetto funzione per altri adattatori. * "Perché non dovrebbe funzionare, dato che non ha captato lambda sono implicitamente convertibili in puntatori di funzione? – ildjarn

+1

@ildjarn: Non penso che un operatore di conversione parteciperà alla deduzione degli argomenti del modello. – kennytm

0

Provare pointer_to_binary_function<string,string,int>(stringcasecmp) anziché ptr_fun(stringcasecmp)?

Problemi correlati