2011-07-29 11 views
8

Esta es una reproducción simplificada que ilustra cómo funciona class Predicate fuera de main(), pero cuando el código exacto aparece en línea como class InlinePredicate, el compilador no puede coincidir con std::sort. Lo extraño es que puede pasar cualquier cosa como el tercer argumento a std::sort (digamos, entero 7) y obtendrá un error de compilación cuando no sea compatible con el operator() que sort espera. Pero cuando pase por debajo pred2 que no coincide en absoluto:¿Por qué falla este predicado std :: sort cuando la clase está dentro de main()?

#include <string> 
#include <vector> 
#include <algorithm> 

using namespace std; 

class Predicate { 
public: 
    bool operator() (const pair<string,int>& a, const pair<string,int>& b) 
    { 
     return a.second < b.second; 
    } 
}; 

int 
main() 
{ 
    vector<pair<string, int> > a; 

    Predicate pred; 
    sort(a.begin(), a.end(), pred); 

    class InlinePredicate { 
    public: 
     bool operator() (const pair<string,int>& a, const pair<string,int>& b) 
     { 
      return a.second < b.second; 
     } 
    } pred2; 
    sort(a.begin(), a.end(), pred2); 

    return 0; 
} 

repro.cc: In function ‘int main()’:

repro.cc:30: error: no matching function for call to ‘sort(__gnu_cxx::__normal_iterator, std::allocator >, int>*, std::vector, std::allocator >, int>, std::allocator, std::allocator >, int> > > >, __gnu_cxx::__normal_iterator, std::allocator >, int>*, std::vector, std::allocator >, int>, std::allocator, std::allocator >, int> > > >, main()::InlinePredicate&)’

+1

Como nota al margen: el operador debe probablemente ser const 'operador booleano() (const par y un par const y b) ** **' const –

Respuesta

9

En 03, las clases locales de C++ tienen ningún vínculo y por lo tanto no se puede utilizar como argumentos de plantilla (§14.3.1/2)

En C++ 0x, esta limitación se ha eliminado y su código se compilará tal cual.

+1

Probablemente aún deba hacer que el operador del predicado 'const', como' sort' podría requerir eso. –

+0

Compila con 'g ++ -std = C++ 0x' para GCC 4.5 (no 4.3, y no tengo 4.4 a mano) –

5

En las versiones de C++ anteriores a C++ 0x, las clases declaradas dentro de las funciones no pueden aparecer en los parámetros de la plantilla. Su invocación de sort lo instancia implícitamente con un parámetro de plantilla establecido en InlinePredicate, que es ilegal.

Puede considerar usar C++ 0x (con GCC, pase --std=c++0x; en C++ 0x este código funcionará como está, o puede usar funciones anónimas en su lugar), o boost::lambda. Con boost::lambda, se vería así:

using namespace boost::lambda; 

sort(a.begin(), a.end(), _1 < _2); 
+1

Tenga en cuenta que a partir de Boost 1.47, Boost.Lambda está oficialmente obsoleto a favor de [Boost . Phoenix v3] (http://www.boost.org/doc/libs/release/libs/phoenix/). En consecuencia, el nuevo código sería mucho mejor usando Phoenix en lugar de Lambda (y la sintaxis que mostró para la llamada 'sort' sería idéntica). – ildjarn

+0

@ildjarn, oh genial, _yet another_ C++ 03 función anónima piratear para aprender ... :) – bdonlan

+0

Pero una mucho más poderosa, definitivamente vale la pena. : -] Incluso en C++ 0x, tiendo a utilizar funtores Phoenix sobre C++ 0x lambdas aproximadamente la mitad de las veces, ya que son polimórficos. – ildjarn

Cuestiones relacionadas