utilidad sobrecargar sobrecargados sobrecarga que pueden operadores operador esta constructores compuesta c++ operator-overloading static-methods

c++ - sobrecargados - sobrecargar operador==



¿Por qué los operadores sobrecargados no se pueden definir como miembros estáticos de una clase? (7)

La sintaxis de C ++ permite definir operadores sobrecargados dentro de la estructura / clase como:

struct X { void operator+(X); }

o fuera de la estructura / clase como:

void operator+(X, X);

pero no como

struct X { static void operator+(X, X); }

¿Algún cuerpo conoce los motivos de esta decisión? ¿Por qué la tercera forma no está permitida? (MSVC da un error de sintaxis). Tal vez hay alguna historia detrás de esto?

ps La presencia de la primera y la segunda definición al mismo tiempo crea ambigüedad:

1>CppTest1.cxx 1>c:/ballerup/misc/cf_html/cpptest1.cxx(39) : error C2593: ''operator +'' is ambiguous 1> c:/ballerup/misc/cf_html/cpptest1.cxx(13): could be ''void B1::operator +(B1 &)'' 1> c:/ballerup/misc/cf_html/cpptest1.cxx(16): or ''void operator +(B1 &,B1 &)'' 1> while trying to match the argument list ''(B1, B1)''

No entiendo por qué esta ambigüedad es mejor que entre 1,3 o 2,3.


Básicamente, un operador estático miembro de la clase no compra nada sobre un miembro no estático.

Cualquier operador definido para una clase debe tomar al menos un argumento de ese tipo de clase.

Un operador miembro toma ese argumento en la forma de this parámetro implícito.

Un operador no miembro tiene un argumento explícito de ese tipo de clase.

La interfaz del operador con la función del operador no le importa; cuando invocamos a + b , nos encargamos de generar el código para pasar a través de this parámetro o como un parámetro explícitamente declarado. Por lo tanto, no estamos expresando ninguna diferencia en los matices con estática versus no estática en cuanto a cómo se usa el operador.

Supongamos que de repente se introdujo un requisito de que el último ISO C ++ debe ser compatible con los operadores miembros estáticos. De prisa, este requisito podría implementarse mediante una reescritura de fuente a fuente de acuerdo con el siguiente patrón:

static whatever class::operator *(class &x) { x.fun(); return foo(x); } --> whatever class::operator *() { (*this).fun(); return foo(*this); } --> whatever class::operator *() { fun(); return foo(*this); }

El compilador reescribe el operador miembro static a no estático, elimina el parámetro más a la izquierda y (con el sombreado correcto wrt de seguridad léxica) reemplaza todas las referencias a ese parámetro con la expresión *this (los usos innecesarios de los cuales se pueden elidir).

Esta transformación es lo suficientemente simple como para que se pueda confiar en el programador para escribir el código de esa manera en primer lugar.

El mecanismo de definición de la función del operador static es menos poderoso. No puede ser virtual por ejemplo, mientras que el no estático puede ser.


Esta podría ser la razón.

Porque cada operator necesita uno o más operands . Entonces, si declaramos que está static , no podemos llamarlo usando objetos (operandos).

Para invocar un operando que no es más que un objeto, la función tiene que ser no estática.

A continuación se muestra una condición que debe cumplirse al sobrecargar la función.

  • Debe tener al menos un operando que sea del tipo definido por el usuario.

Supongamos que declaramos que nuestra función de sobrecarga del operador es estática. Entonces la 1ra de todas las condiciones anteriores no será satisfecha.

Otra razón es que dentro de las funciones estáticas solo podemos acceder a los miembros de datos estáticos. Pero mientras hacemos una sobrecarga de operadores, tenemos que acceder a todos los miembros de datos. Entonces, si declaramos que nuestra función de sobrecarga del operador es estática, no podemos acceder a todos los miembros de los datos.

Por lo tanto, la función de sobrecarga del operador debe ser una non-static member function .

Pero hay una excepción.

Si utilizamos una función amiga para la sobrecarga del operador, entonces puede declararse como estática.


Las funciones de miembro estático se pueden usar para utilidades que ayudan a una clase, pero por una razón u otra no son miembros. Es fácil imaginar que entre las utilidades expresadas como funciones miembro de clase estática, podría ser útil tener operadores.

Por supuesto, si un operador sobrecargado toma una clase C como su argumento principal, no hay una buena razón para querer que sea un miembro estático de la clase C. Puede ser simplemente un miembro no estático, por lo que obtiene ese argumento implícitamente.

Sin embargo, un miembro estático de la clase C podría ser un operador sobrecargado en alguna clase que no sea C.

Diga que existe un operator ==(const widget &, const widget &); alcance de archivo operator ==(const widget &, const widget &); . En mi clase de squiggle , estoy trabajando con objetos de widget , pero quiero una comparación diferente para ellos.

Debería poder hacer un static squiggle::operator == (const widget &, const widget &); para mí.

Desde el alcance de clase, esto es fácil de llamar:

void squiggle::memb(widget a, widget b) { if (a == b) { ... } // calls static == operator for widgets }

desde fuera del alcance de la clase, solo podemos llamarlo usando la resolución de alcance explícita combinada con la sintaxis explícita de llamada del operador:

void nonmemb(widget a, widget b) { a == b; // calls the widget member function or perhaps nonstatic operator squiggle::operator ==(a, b); // calls squiggle class'' utility }

Ésta no es una mala idea. Además, podemos hacerlo con funciones sobrecargadas regulares, pero no con operadores. Si la comparación de widgets se realiza con una función de compare , puede haber una compare no miembro o un widget::compare y puede haber un squiggle::compare que tome widgets .

Entonces, el único aspecto de esto que no se admite en C ++ es el azucar sintáctico con los operadores.

Tal vez no sea una idea lo suficientemente útil como para merecer apoyo (¡hasta ahora!). Después de todo, esto no es algo que permita una reorganización revolucionaria de un programa en C ++. Pero arreglaría una incompletud en el lenguaje.

Además, considere que las sobrecargas de clases de operadores new y delete son implícitamente estáticas . Entonces, lo incompleto ya tiene una pequeña excepción.


No estoy al tanto de ningún inconveniente directo que permita que el operador estático + pueda causar (tal vez pensar lo suficiente producirá alguna teoría). Pero creo que al menos el principio "no pagues por lo que no usas" declarado por Bjarne Stroustrup ya es una buena respuesta. ¿Qué ganarás si se permite ese operador estático a excepción de una sintaxis más complicada (tendrás que escribir "X :: operator +" en todas partes en lugar de solo "+")?


No tengo conocimiento específico de ninguna discusión en C ++ sobre este concepto, así que no dude en ignorar esto.

Pero para mí, tienes la pregunta al revés. La pregunta debería ser, "¿por qué se permite esta sintaxis?"

No proporciona ninguna ventaja sobre la sintaxis actual. La versión de la función miembro no estática tiene el mismo acceso a los miembros privados que la versión estática propuesta. Por lo tanto, si necesita acceder a las partes privadas para implementarlo, simplemente conviértalo en un miembro no estático, exactamente como generalmente lo hace con la mayoría de los miembros de una clase.

No facilita la implementación de operadores asimétricos (es decir: operator+(const X &x, const Y &y) ). Si necesita acceso privado para implementar esto, aún necesita una declaración de amigo para ellos en una de las clases.

Entonces diría que la razón por la que no existe es que no es necesario . Entre las funciones que no son miembros y los miembros no estáticos, se cubren todos los casos de uso necesarios.

O, para decirlo de otra manera:

Las funciones gratuitas pueden hacer todo lo que el sistema de función estática puede hacer, y más .

Mediante el uso de funciones gratuitas, puede obtener una búsqueda dependiente de los argumentos para los operadores utilizados en las plantillas. No puede hacer eso con funciones estáticas, porque esas deberían ser miembros de una clase en particular. Y no puede agregar a una clase desde fuera de la clase, mientras que puede agregar a un espacio de nombres. Entonces, si necesita poner un operador en un espacio de nombre particular para que funcione algún código ADL, puede hacerlo. No puede hacer eso con operadores de funciones estáticas.

Por lo tanto, las funciones gratuitas son un superconjunto de todo lo que proporcionaría el sistema de función estática propuesto. Dado que no hay ningún beneficio para permitirlo, no hay ninguna razón para permitirlo y, por lo tanto, no está permitido.

lo que haría posible el uso de funtores sin instanciarlos?

Esa es una contradicción en los términos. Un "functor" es un "objeto de función". Un tipo no es un objeto ; por lo tanto, no puede ser un funtor. Puede ser un tipo que, cuando se crea una instancia, dará como resultado un funtor. Pero el tipo solo no será un funtor.

Además, poder declarar Typename::operator() static no significaría que Typename() haría lo que quisiera. Esa sintaxis ya tiene un significado real: instanciar un Typename temporal llamando al constructor predeterminado.

Por último, incluso si todo eso no fuera el caso, ¿de qué serviría eso realmente? La mayoría de las funciones de plantilla que toman un tipo de llamada de algún tipo funcionan igual de bien con un puntero de función como con un functor. ¿Por qué querrías restringir tu interfaz, no solo a funtores, sino a funtores que no pueden tener datos internos? Eso significa que no podrás pasar capturando lambdas y demás.

¿De qué sirve un functor que no puede contener el estado? ¿Por qué quiere obligar al usuario a pasar "funtores" que no tienen estado? ¿Y por qué quieres evitar que el usuario pueda usar lambdas?

Entonces su pregunta se deriva de una suposición falsa: incluso si la tuviéramos, no le daría lo que quiere.


Porque no hay una sintaxis obvia para llamar a un operador así, lo que significaría que tendríamos que inventar algo. Considere las siguientes variables:

X x1; X x2;

Ahora, imaginemos por un momento que estamos usando funciones miembro normales en lugar de operadores, digamos que cambié operator+ a plus en su ejemplo.

Cada una de las tres llamadas se vería así:

x1.plus(x2); plus(x1, x2); X::plus(x1, x2);

Ahora, al hacer una llamada de operador usando + ¿cómo sabría el compilador buscar su operador en el alcance de X ? No puede hacerlo para funciones miembro estáticas normales, y los operadores no reciben una dispensación especial para desambiguar.

Ahora considere si tenía los formularios segundo y tercero declarados en su programa. Si dijera x1 + x2 el compilador tendría que elegir siempre la función libre o la llamada sería ambigua. La única alternativa real sería algo como x1 X::+ x2 que simplemente se ve feo. Teniendo en cuenta todo eso, estoy seguro de que el comité de estándares decidió simplemente prohibir la versión de miembro estático ya que cualquier cosa que pudiera lograr podría hacerse con una función de amigo libre.


hmmm ... Estoy pensando en un operador estático () que eliminaría implícitamente todos los constructores ... Eso nos daría un tipo de funciones mecanografiadas. A veces desearía tenerlo en C ++.