2011-12-12 11 views
5

Tengo el siguiente programa que usa ptr_fun con una función lambda.ptr_fun con una función 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"; 
} 

Recibo los siguientes mensajes de error.

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

¿Cómo puedo modificar el código (mínimamente) para que se compile?

+1

Sólo una pequeña nota al margen: Si usted está planeando sobre el uso de un lambda como el que tienen aquí mucho, es posible que Considere pasar los argumentos como referencia. Ahorre gran cantidad de copia de cadenas. –

+0

¡Es posible que su lambda 'stringcasecmp' sea recursiva! – quamrana

+0

@quamrana ¿Por qué es recursivo? – ggg

Respuesta

9

bind2nd (§D.9) y ptr_fun (§D.8.2.1) están en desuso en C++ 11. Se podía escribir otra función lambda en find_if:

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

ptr_fun(<lambda>) no va a funcionar, porque ptr_fun está diseñado para C++ 03 para convertir un puntero de función a un objeto de función para otros adaptadores. Una lambda ya es un objeto de función, por lo que ptr_fun es innecesario.

bind2nd espera que el objeto de la función de definir los miembros second_argument_type y result_type, lo cual no es cierto para un lambda, por lo que escribir bind2nd(<lambda>, target) no va a funcionar bien. Pero en C++ 11 no es un sustituto genérico que funciona:

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

Sin embargo, bind no devuelve un objeto de función 03 de estilo C++, que está a la espera not1: se requiere el tipo de resultado de bind para definir el miembro argument_type que no existe. Por lo tanto, la expresión final

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

se no trabajo. La solución más simple es usar otra lambda que escribí arriba.

Alternativamente, se podría definir un negador genérica:

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

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

+0

Gracias. Creo que es bastante extraño que bind2nd esté en desuso, pero el enlace C++ 11 no funciona con not1. – ggg

+0

"*' ptr_fun () 'no funcionará, porque' ptr_fun' está diseñado para que C++ 03 convierta un puntero de función a un objeto de función para otros adaptadores. * "Por qué no debería funcionar, sin embargo, dado que no captura lambdas son implícitamente convertibles a indicadores de función? – ildjarn

+1

@ildjarn: No creo que un operador de conversión participe en la deducción del argumento de la plantilla. – kennytm

0

Probar pointer_to_binary_function<string,string,int>(stringcasecmp) en lugar de ptr_fun(stringcasecmp)?

Cuestiones relacionadas