2010-11-01 12 views
15

Cuando uso el algoritmo de clasificación STL en un vector, quiero pasar mi propia función de comparación que también toma un parámetro.Pasar un parámetro a una función de comparación?

Por ejemplo, lo ideal es que quieren hacer una declaración de función local, como:

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    bool comp(int i, int j) { 
     // logic uses paramA in some way... 
    } 

    sort(v.begin(), v.end(), comp); 
} 

Sin embargo, el compilador se queja de eso. Cuando intento algo como:

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    struct Local { 
     static bool Compare(int i, int j) { 
      // logic uses paramA in some way... 
     } 
    }; 

    sort(v.begin(), v.end(), Local::Compare); 
} 

El compilador todavía se queja: "Error: el uso del parámetro de la función que contiene"

¿Qué debo hacer? ¿Debo hacer algunas variables globales con una función de comparación global ...?

Gracias.

Respuesta

22

No se puede acceder a las variables locales de una función desde una función definida localmente - C++ en su forma actual no permite closures. La próxima versión del lenguaje, C++ 0x, admitirá esto, pero el estándar de lenguaje no se ha finalizado y hay poco apoyo para el borrador del estándar actual en este momento.

Para que esto funcione, debe cambiar el tercer parámetro de std::sort para que sea una instancia de objeto en lugar de una función. El tercer parámetro de std::sort puede ser cualquier elemento que se pueda llamar (es decir, cualquier x donde agregar paréntesis como x(y, z) tiene sentido sintáctico). La mejor manera de hacer esto es definir una estructura que implementa la función operator() y, a continuación, pasar una instancia de ese objeto:

struct Local { 
    Local(int paramA) { this->paramA = paramA; } 
    bool operator() (int i, int j) { ... } 

    int paramA; 
}; 

sort(v.begin(), v.end(), Local(paramA)); 

Tenga en cuenta que tenemos que almacenar paramA en la estructura, ya que no pueden acceder de lo contrario, desde operator().

+0

El tercer parámetro es cualquier cosa que se puede llamar utilizando la sintaxis de llamada de función. Entonces, tanto una función como una clase/estructura que define 'operator()' harán el truco. –

+0

@Eugen: Buen punto, he actualizado mi respuesta para reflejar eso. –

+0

Gracias, eso está funcionando (excepto que el compilador se queja a menos que mueva la declaración struct fuera de la función principal. Pensé que se nos permitía declarar clases y estructuras localmente ...?) – George41

10

En C++ no se puede definir una función libre dentro de otra función. Por lo tanto, su primer fragmento de código está mal formado.

sort(v.begin(), v.end(), Local::Compare);

El tercer argumento debe ser un objeto de función. Sobrecarga al operador () dentro de la clase y luego crea el objeto de función.


En C++ 0x puede usar lambda expressions.

auto comp = [&](int m,int n)-> bool { 

     return m<n; //or use paramA in some way 
    }; 

sort(v.begin(), v.end(), comp); 
+0

En mi opinión, una solución mucho mejor que la exceptuada debido al uso de bonitas funciones de C++ (lambda) – Anonymous

4

Una posibilidad es pasar el parámetro cuando construye su objeto de comparación:

class cmp { 
    int param; 
public: 
    cmp(int p) : param(p) {} 

    bool operator()(int i, int j) { 
     // logic uses param 
    } 
}; 

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    sort(v.begin(), v.end(), cmp(paramA)); 
} 
Cuestiones relacionadas