sort program geeksforgeeks geeks geek for example array c++ templates stl functor

c++ - program - vector geek for geeks



¿Por qué los functores STL están en su plantilla y no su operador de llamada de función? (2)

Los funtores STL se implementan así:

template<class T> struct less{ bool operator()(T const& lhs, T const& rhs){ return lhs < rhs; } };

Esto nos hace mencionar el tipo (posiblemente largo) cada vez que creamos tal funtor. ¿Por qué no se implementan como se muestra a continuación? ¿Alguna razón?

struct less{ template<class T> bool operator()(T const& lhs, T const& rhs){ return lhs < rhs; } };

Eso los haría utilizables sin ninguna mención de tipos (posiblemente largos).


Tal vez:

std::multiset<long, std::less<int> > moduloset;

Lo extraño es hacer, pero el punto es que std::less<int> , std::less<long> , std::less<unsigned int> implementan diferentes funciones matemáticas que producen diferentes resultados cuando se aprueban (el resultado de la conversión) ciertas expresiones de argumento. Varios algoritmos y otros componentes estándar de la biblioteca funcionan especificando un functor, por lo que tiene sentido para mí que haya diferentes funtores para representar esas diferentes funciones matemáticas, no solo diferentes sobrecargas de operator() en un funtor.

Además, un functor con un operator() plantilla operator() no puede ser un Predicado Binario Adaptable, ya que no tiene tipos de argumentos (un argumento puede tener cualquier tipo). Entonces, si std::less se definiera como sugieres, entonces no podría participar en el contenido en <functional> .

También en una nota altamente especulativa: std::less probablemente se diseñó antes de que el soporte para las funciones de miembros de la plantilla se generalizara, ya que hay varias notas en la documentación de SGI STL que dicen "si su implementación no admite plantillas de miembros, entonces esto no está disponible ". Para un componente tan simple, supongo que sería un incentivo para hacer algo que funcione hoy. Una vez que existe, la estandarización podría haberla eliminado en favor de otra cosa, pero ¿valía la pena interrumpir el código existente? Si fuera tan importante, entonces usted o el estándar podrían introducir un functor flexible_less como usted lo describe.

Finalmente, por que

template<class T> bool operator()(T const& lhs, T const& rhs){ return lhs < rhs; }

más bien que

template<class T, class U> bool operator()(T const& lhs, U const& rhs){ return lhs < rhs; }

Para los tipos definidos por el usuario, los dos podrían no ser los mismos. Sí, esta es una pregunta injusta, ya que no sé por qué no hay una versión de doble argumento de std::less ;-)


También haría imposible especializarlos para tipos definidos por el usuario.

Se supone que son un punto de personalización.

Para resumir las discusiones en los comentarios:

Aunque es técnicamente posible hacer lo que Xeo sugiere, el estándar de lenguaje no lo permite.

Es muy difícil escribir una plantilla de clase trabajadora si los usuarios pueden especializar funciones individuales de la plantilla. Sin embargo, en algunos casos puede ser una buena idea especializar a toda la clase para un tipo definido por el usuario.

Por lo tanto, el estándar C ++ 98 escribe (17.4.3.1):

No está definido para un programa de C ++ agregar declaraciones o definiciones al espacio de nombres estándar o a los espacios de nombres dentro del espacio de nombres estándar, a menos que se especifique lo contrario. Un programa puede agregar especializaciones de plantillas para cualquier plantilla de biblioteca estándar al espacio de nombres estándar.

Como no está "especificado de otra manera" que el código de Xeo está permitido, debemos entender que no lo está. ¡Quizás no sea del todo obvio! O que las "especializaciones de plantillas" solo se aplican a las clases.

El nuevo estándar C ++ 11 ha tenido esta parte expandida y la explica con más detalle (17.6.4.2):

El comportamiento de un programa de C ++ no está definido si agrega declaraciones o definiciones al espacio de nombres estándar o a un espacio de nombres dentro del espacio de nombres estándar, a menos que se especifique lo contrario. Un programa puede agregar una especialización de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombres estándar solo si la declaración depende de un tipo definido por el usuario y la especialización cumple con los requisitos de biblioteca estándar para la plantilla original y no está explícitamente prohibida.

El comportamiento de un programa en C ++ no está definido si declara

- una especialización explícita de cualquier función miembro de una plantilla de clase de biblioteca estándar, o
- una especialización explícita de cualquier plantilla de función miembro de una clase de biblioteca estándar o plantilla de clase, o
- una especialización explícita o parcial de cualquier plantilla de clase miembro de una clase de biblioteca estándar o plantilla de clase.

Un programa puede crear una instancia explícita de una plantilla definida en la biblioteca estándar solo si la declaración depende del nombre de un tipo definido por el usuario y la instanciación cumple con los requisitos de la biblioteca estándar para la plantilla original.