c++ - instalar - google tag manager paso a paso
¿Por qué el código en la mayoría de las implementaciones de STL está tan complicado? (6)
Las implementaciones varían. libc++ por ejemplo, es mucho más fácil en los ojos. Todavía hay un poco de ruido de subrayado sin embargo. Como otros han señalado, desafortunadamente los guiones bajos son necesarios. Aquí está la misma función en libc ++:
template <class _Compare, class _BidirectionalIterator>
bool
__next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp)
{
_BidirectionalIterator __i = __last;
if (__first == __last || __first == --__i)
return false;
while (true)
{
_BidirectionalIterator __ip1 = __i;
if (__comp(*--__i, *__ip1))
{
_BidirectionalIterator __j = __last;
while (!__comp(*__i, *--__j))
;
swap(*__i, *__j);
_STD::reverse(__ip1, __last);
return true;
}
if (__i == __first)
{
_STD::reverse(__first, __last);
return false;
}
}
}
El STL es una pieza crítica del mundo C ++, la mayoría de las implementaciones se derivan de los esfuerzos iniciales de Stepanov y Musser.
A mi pregunta se le da la criticidad del código, y es una de las fuentes principales para que las personas vean ejemplos de C ++ bien escrito, tanto para asombro como para propósitos de aprendizaje: ¿Por qué las diversas implementaciones de la STL son tan repugnantes de ver? En general, buenos ejemplos de cómo no escribir código C ++ desde un punto de vista estético.
Los ejemplos de código a continuación no aprobarían la revisión de código en los lugares en los que he trabajado por razones que varían desde la denominación de variables, el diseño, las macros y los usos de los operadores que requieren más que una simple mirada para descubrir qué está ocurriendo realmente.
template<class _BidIt> inline
bool _Next_permutation(_BidIt _First, _BidIt _Last)
{ // permute and test for pure ascending, using operator<
_BidIt _Next = _Last;
if (_First == _Last || _First == --_Next)
return (false);
for (; ; )
{ // find rightmost element smaller than successor
_BidIt _Next1 = _Next;
if (_DEBUG_LT(*--_Next, *_Next1))
{ // swap with rightmost element that''s smaller, flip suffix
_BidIt _Mid = _Last;
for (; !_DEBUG_LT(*_Next, *--_Mid); )
;
_STD iter_swap(_Next, _Mid);
_STD reverse(_Next1, _Last);
return (true);
}
if (_Next == _First)
{ // pure descending, flip all
_STD reverse(_First, _Last);
return (false);
}
}
}
_Ty operator()()
{ // return next value
static _Ty _Zero = 0; // to quiet diagnostics
_Ty _Divisor = (_Ty)_Mx;
_Prev = _Mx ? ((_Ity)_Ax * _Prev + (_Ty)_Cx) % _Divisor
: ((_Ity)_Ax * _Prev + (_Ty)_Cx);
if (_Prev < _Zero)
_Prev += (_Ty)_Mx;
return (_Prev);
}
Tenga en cuenta que no estoy criticando la interfaz, ya que está muy bien diseñada y es aplicable. Lo que me preocupa es la legibilidad de los detalles de la implementación.
Una pregunta similar ha sido planteada previamente:
¿Existe una implementación legible de la STL?
¿Por qué la implementación de STL es tan ilegible? ¿Cómo C ++ podría haber sido mejorado aquí?
Nota: El código presentado anteriormente se tomó de los encabezados de cola y algoritmo de MSVC 2010.
Neil Butterworth, ahora listado como "anon", proporcionó un enlace útil en su respuesta a la pregunta de SO "¿Existe una implementación legible de la STL?" . Citando su respuesta allí:
Hay un libro The C ++ Standard Template Library, coautor de los diseñadores originales de STL Stepanov & Lee (junto con PJ Plauger y David Musser), que describe una posible implementación, completa con el código, consulte http://www.amazon.co.uk/C-Standard-Template-Library/dp/0134376331 .
Vea también las otras respuestas en ese hilo.
De todos modos, la mayoría del código STL (por STL aquí me refiero a un subconjunto similar a STL de la biblioteca estándar de C ++) es un código de plantilla, y como tal debe ser solo de cabecera, y como se usa en casi todos los programas, vale la pena tener eso Código lo más corto posible.
Por lo tanto, el punto de intercambio natural entre concisión y legibilidad está mucho más lejos en el extremo de concisión de la escala que con el código "normal".
Además, la biblioteca estándar es donde la vista del código de la aplicación independiente del sistema está conectada al sistema subyacente, utilizando todo tipo de elementos específicos del compilador de los que usted, como desarrollador de aplicaciones, debería mantenerse alejado.
Nombres de variables por la razón de que este es un código de biblioteca estándar, y debe usar nombres reservados para los detalles de implementación en los encabezados. Lo siguiente no debe romper las bibliotecas estándar:
#define mid
#include <algorithm>
Por lo tanto, los encabezados de biblioteca estándar no pueden usar mid
como nombre de variable, por _Mid
tanto _Mid
. El STL era diferente, no era parte de la especificación del lenguaje, se definió como "aquí hay algunos encabezados, utilícelos como quiera"
Su código o el mío, por otro lado, no serían válidos si utilizara _Mid
como nombre de variable, ya que es un nombre reservado; la implementación tiene permitido hacerlo:
#define _Mid
si se siente asi
Diseño - meh. Probablemente tengan una guía de estilo, probablemente la sigan, más o menos. El hecho de que no coincida con mi guía de estilo (y por lo tanto, fallaría en mi revisión del código) no es nada para ellos.
Operadores que son difíciles de resolver, ¿a quién? El código debe escribirse para las personas que lo mantienen, y GNU / Dinkumware / quienquiera que no quiera dejar que la gente pierda las bibliotecas estándar que no pueden descifrar *--_Next
de un vistazo. Si usas ese tipo de expresión, te acostumbras a él y, si no lo haces, seguirás encontrando dificultades.
Te daré, sin embargo, esa sobrecarga del operator()
es una tontería. [Editar: lo entiendo, es un generador lineal congruente, hecho de manera muy genérica, y si el módulo es "0", eso significa que solo se usa el envolvente natural del tipo aritmético.]
Para agregar lo que la gente ya ha dicho, el estilo que ves es el estilo GNU. ¿Feo? Tal vez, eso está en el ojo del espectador. Pero es un estilo estrictamente definido, y hace que todos los códigos se vean similares, en lugar de resistentes a acostumbrarse.
Sobre los nombres de las variables, los implementadores de bibliotecas deben usar convenciones de denominación "locas", como los nombres que comienzan con un guión bajo seguido de una letra mayúscula, porque dichos nombres están reservados para ellos. No pueden usar nombres "normales", ya que estos pueden haber sido redefinidos por una macro de usuario.
La sección 17.6.3.3.2 "Nombres globales" §1 establece:
Ciertos conjuntos de nombres y firmas de funciones siempre están reservados para la implementación:
Cada nombre que contiene un doble guión bajo o comienza con un guión bajo seguido de una letra mayúscula se reserva a la implementación para cualquier uso.
Cada nombre que comienza con un guión bajo está reservado a la implementación para su uso como un nombre en el espacio de nombres global.
(Tenga en cuenta que estas reglas prohíben guardias de encabezado como __MY_FILE_H
que he visto con bastante frecuencia).
Sospecho que parte de la razón es que el código en el STL está altamente optimizado. El tipo de código que se está implementando tiene un rendimiento mucho más importante que la legibilidad. Debido a que son tan utilizados, tiene sentido hacerlos lo más rápido posible.