¿Qué nuevas capacidades agregan los literales definidos por el usuario a C ++?


139

C ++ 11 Presenta literales definidos por el usuario que permitirán la introducción de nueva sintaxis literal basado en literales existentes ( int, hex, string, float) de modo que cualquier tipo serán capaces de tener una presentación literal.

Ejemplos:

// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{ 
    return std::complex<long double>(0, d); 
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)

// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42

// std::string
std::string operator "" _s(const char* str, size_t /*length*/) 
{ 
    return std::string(str); 
}

auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

A primera vista, esto se ve muy bien, pero me pregunto qué tan aplicable es realmente, cuando traté de pensar en tener los sufijos _ADy _BCcrear fechas, descubrí que es problemático debido al orden del operador. 1974/01/06_ADprimero evaluaría 1974/01(como simple int) y solo más tarde el 06_AD(sin mencionar que agosto y septiembre tienen que escribirse sin el 0por razones octales). Esto se puede solucionar haciendo que la sintaxis sea 1974-1/6_ADpara que el orden de evaluación del operador funcione pero sea torpe.

Entonces, mi pregunta se reduce a esto, ¿crees que esta característica se justificará? ¿Qué otros literales le gustaría definir que harán que su código C ++ sea más legible?


Sintaxis actualizada para ajustarse al borrador final en junio de 2011


8
Voy a votar para cerrar esto. El título es claramente inflamatorio.
Cachorro

76
@DeadMG, si tiene un problema con el título, puede editarlo. Es un poco divertido tratar de cerrar una pregunta de 3 años que tiene 11 votos a favor y 8 favoritos. (Sin mencionar que la etiqueta en este sitio ha cambiado en los últimos 3 años).
Motti

55
Creo que tiene un error en sus ejemplos: string operator "" _s(const char*s);"no se puede usar para analizar "hello"_s". Este es un literal de cadena y buscará el operador con un size_tparámetro adicional . Estoy en lo cierto?
Towi

1
Una cosa que me he preguntado es si tendría sentido escribir "C portátil" en C ++, reemplazando tipos como uint16_tcuyo comportamiento depende de la implementación, con tipos similares uwrap16y unum16cuyo comportamiento sería independiente de la implementación, de modo que dadas uwrap16 w=1; unum16 n=1;las expresiones w-2y n-2produciría (uwrap16)65535y (int)-1, respectivamente [ uint16_tproduciría el primer resultado en sistemas donde intes de 16 bits, y el segundo en sistemas donde intes más grande]. El mayor problema que vi fue el manejo de literales numéricos.
supercat

1
Ser capaz de hacer que los literales numéricos interactúen sin problemas con otros tipos numéricos de comportamiento definido parecería que debería permitir que tales tipos se usen para crear un lenguaje en el que el código que desea realizar acciones dependientes de la implementación podría hacerlo sin tener que depender de la implementación. comportamientos definidos. Hay algunos lugares donde el BID seguirá siendo inevitable porque cosas como las diferencias de puntero y los sizeoftipos de enteros devueltos dependen de la implementación, pero la situación aún podría mejorarse mucho más de lo que es. ¿Qué pensarías de ese concepto?
supercat

Respuestas:


71

Aquí hay un caso en el que hay una ventaja de usar literales definidos por el usuario en lugar de una llamada de constructor:

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

La ventaja es que una excepción en tiempo de ejecución se convierte en un error en tiempo de compilación. No podría agregar la aserción estática al controlador de conjunto de bits que toma una cadena (al menos no sin argumentos de plantilla de cadena).


77
Podrías hacer lo mismo dando a std :: bitset un constructor constexpr adecuado.
Nicol Bolas

1
@NicolBolas Tienes razón. De hecho, me sorprende que uno no esté allí. Tal vez deberíamos proponer uno o dos para 2014 si no es demasiado tarde.
Emsr

192

A primera vista, parece ser un azúcar sintáctico simple.

Pero cuando miramos más profundamente, vemos que es más que azúcar sintáctica, ya que amplía las opciones del usuario de C ++ para crear tipos definidos por el usuario que se comportan exactamente como los distintos tipos integrados. En esto, este pequeño "bonus" es una adición muy interesante de C ++ 11 a C ++.

¿Realmente lo necesitamos en C ++?

Veo pocos usos en el código que escribí en los últimos años, pero solo porque no lo use en C ++ no significa que no sea interesante para otro desarrollador de C ++ .

Habíamos usado en C ++ (y en C, supongo), literales definidos por el compilador, para escribir números enteros como enteros cortos o largos, números reales como flotante o doble (o incluso doble largo) y cadenas de caracteres como caracteres normales o anchos. .

En C ++, teníamos la posibilidad de crear nuestros propios tipos (es decir, clases), potencialmente sin sobrecarga (en línea, etc.). Tuvimos la posibilidad de agregar operadores a sus tipos, para que se comporten como tipos incorporados similares, lo que permite a los desarrolladores de C ++ usar matrices y números complejos tan naturalmente como lo harían si se hubieran agregado al lenguaje en sí. Incluso podemos agregar operadores de conversión (que generalmente es una mala idea, pero a veces, es la solución correcta).

Todavía nos faltó una cosa para que los tipos de usuario se comporten como tipos incorporados: literales definidos por el usuario.

Por lo tanto, supongo que es una evolución natural para el lenguaje, pero para ser lo más completo posible: " Si desea crear un tipo, y desea que se comporte lo más posible que los tipos incorporados, aquí están las herramientas. .. "

Supongo que es muy similar a la decisión de .NET de hacer que cada primitiva sea una estructura, incluidos booleanos, enteros, etc., y que todas las estructuras se deriven de Object. Esta decisión por sí sola pone a .NET mucho más allá del alcance de Java cuando se trabaja con primitivas, sin importar la cantidad de hacks de boxeo / unboxing que Java agregará a su especificación.

¿Realmente lo necesitas en C ++?

Esta pregunta es para USTED contestar. No Bjarne Stroustrup. No Herb Sutter. No es el miembro del comité estándar de C ++. Es por eso que tiene la opción en C ++ , y no restringirán una notación útil solo a los tipos integrados.

Si lo necesita, entonces es una adición bienvenida. Si no lo haces, bueno ... No lo uses. No te costará nada.

Bienvenido a C ++, el lenguaje donde las características son opcionales.

¿¿¿Hinchado??? Muéstrame tus complejos !!!

Hay una diferencia entre hinchado y complejo (juego de palabras).

Como lo muestra Niels en ¿Qué nuevas capacidades agregan los literales definidos por el usuario a C ++? , poder escribir un número complejo es una de las dos características agregadas "recientemente" a C y C ++:

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

Ahora, tanto el tipo "doble complejo" C99 como el tipo "std :: complex" de C ++ pueden multiplicarse, sumarse, restarse, etc., utilizando la sobrecarga del operador.

Pero en C99, simplemente agregaron otro tipo como un tipo incorporado y soporte de sobrecarga del operador incorporado. Y agregaron otra característica literal incorporada.

En C ++, solo usaron las características existentes del lenguaje, vieron que la característica literal era una evolución natural del lenguaje y, por lo tanto, la agregaron.

En C, si necesita la misma mejora de notación para otro tipo, no tiene suerte hasta su cabildeo para agregar sus funciones de onda cuántica (o puntos 3D, o cualquier tipo básico que esté usando en su campo de trabajo) al El estándar C como tipo incorporado tiene éxito.

En C ++ 11, puedes hacerlo tú mismo:

Point p = 25_x + 13_y + 3_z ; // 3D point

¿Está hinchado? No , la necesidad está ahí, como se muestra por cómo los complejos C y C ++ necesitan una forma de representar sus valores complejos literales.

¿Está mal diseñado? No , está diseñado como cualquier otra característica de C ++, teniendo en cuenta la extensibilidad.

¿Es solo para fines de notación? No , ya que incluso puede agregar seguridad de tipo a su código.

Por ejemplo, imaginemos un código orientado a CSS:

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

Entonces es muy fácil imponer un tipeo fuerte a la asignación de valores.

¿Es peligroso?

Buena pregunta. ¿Pueden estas funciones tener espacios de nombres? Si es así, entonces Jackpot!

De todos modos, como todo, puedes matarte si una herramienta se usa incorrectamente . C es poderoso, y puedes dispararte si usas mal la pistola C. C ++ tiene la pistola C, pero también el bisturí, la pistola y cualquier otra herramienta que encuentres en el kit de herramientas. Puedes usar mal el bisturí y desangrarte hasta morir. O puede crear un código muy elegante y robusto.

Entonces, como todas las funciones de C ++, ¿realmente lo necesita? Es la pregunta que debe responder antes de usarlo en C ++. Si no lo hace, no le costará nada. Pero si realmente lo necesita, al menos, el idioma no lo defraudará.

El ejemplo de la fecha?

Me parece que su error es que está mezclando operadores:

1974/01/06AD
    ^  ^  ^

Esto no se puede evitar, porque / siendo un operador, el compilador debe interpretarlo. Y, AFAIK, es algo bueno.

Para encontrar una solución a su problema, escribiría el literal de alguna otra manera. Por ejemplo:

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

Personalmente, elegiría el entero y las fechas ISO, pero depende de SUS necesidades. Cuál es el objetivo de dejar que el usuario defina sus propios nombres literales.


1
Gracias, yo y mis otras personalidades alternativas han sido descubiertas. Más en serio, escribí esto solo, pero tal vez estoy usando la expresión de mi lengua materna y no se traducen bien al inglés.
paercebal

En cuanto a las "partes diferentes", como lo muestran sus títulos, lo siento, creo que esto organiza una publicación bastante larga. En cuanto al texto en negrita, es el resumen del párrafo en el que se encuentran. Las personas que desean solo la información sin justificación pueden limitar su lectura en los títulos y el texto en negrita.
paercebal

3
+1. Muy buena explicación. Estamos esperando que esto se implemente. Es realmente importante para nosotros. Trabajamos en MDE (Model-Driven Engineering) y consideramos que es una necesidad. Añado una respuesta a continuación para explicar nuestro caso.
Diego Sevilla

9
@TGV: you can write 1+2i, but you still can't write a+bi, so there's absolutely no pointincluso ignorar su a+biejemplo es ridículo, el hecho de que lo perciba como "baja frecuencia" no significa que todos lo hagan. . . Mirando el panorama general, el punto es asegurarse de que los objetos definidos por el usuario puedan ser considerados como ciudadanos de primera clase del idioma, al igual que los tipos incorporados. Entonces, si puedes escribir 1.5fy 1000UL, ¿por qué no podrías escribir 25io incluso 100101b? Al contrario de C y Java, los tipos de usuario no deben considerarse ciudadanos de segunda clase del lenguaje en C ++.
paercebal

3
@Anton:: Most of data still comes from IOHay muchos valores codificados en el código. Mire todos los booleanos, todos los enteros, todos los dobles que vienen en el código, porque es más conveniente escribir en x = 2 * y ;lugar de x = Two * ydonde Twoes una constante fuertemente tipada . Los literales definidos por el usuario nos permiten ponerle un tipo y escribir: x = 2_speed * y ;y hacer que el compilador verifique que el cálculo tenga sentido. . . Todo se trata de escribir fuerte. . . Quizás no lo uses. Pero seguro que lo haré, tan pronto como pueda usar un compilador habilitado para C ++ 11 en el trabajo.
paercebal

36

Es muy bueno para el código matemático. Fuera de mi mente puedo ver el uso de los siguientes operadores:

grados por grados. Eso hace que escribir ángulos absolutos sea mucho más intuitivo.

double operator ""_deg(long double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

También se puede usar para varias representaciones de punto fijo (que todavía están en uso en el campo de DSP y gráficos).

int operator ""_fix(long double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

Estos parecen buenos ejemplos de cómo usarlo. Ayudan a hacer que las constantes en el código sean más legibles. Es otra herramienta para hacer que el código también sea ilegible, pero ya tenemos tantas herramientas abusadas que una más no hace mucho daño.


1
"pero ya tenemos tantas herramientas abusadas que una más no hace mucho daño " . Vaya, espero que esa no sea la filosofía detrás de toda la inundación de la característica c ++ [x] 1234567890 recientemente. Imagine tener que aprender una biblioteca que usa todos esos, más diez formatos de archivo para la configuración y dos herramientas para el procesamiento previo y posterior de su código ...
masterxilo

@masterxilo Por supuesto, en realidad, su ejemplo es absurdo: los UDL no son más difíciles de aprender que las funciones, ya que solo son sintaxis para ellos, y además, cualquier buena lib solo usa las funciones necesarias para mejorar UX, y documenta exactamente lo que todos los medios. Si alguien usa en exceso una función para generar código ilegible (suponiendo que sea evitable en su línea de trabajo ...), no culpa a esa función, solo al uso. Además, lo ilegible de una persona es el pan y la mantequilla de otra. Es todas las opiniones y opciones . Si no te gustan, ¡no te preocupes! No tienes que usarlos. Otros pueden .
underscore_d

17

Los UDL tienen espacios de nombres (y pueden importarse mediante declaraciones / directivas, pero no puede explícitamente el espacio de nombres un literal como 3.14std::i ), lo que significa que (con suerte) no habrá un montón de enfrentamientos.

El hecho de que en realidad puedan ser moldeados (y constexpr'd) significa que puedes hacer algunas cosas bastante poderosas con UDL. Los autores de Bigint estarán muy contentos, ya que finalmente pueden tener constantes arbitrariamente grandes, calculadas en tiempo de compilación (a través de constexpr o plantillas).

Estoy triste porque no veremos un par de literales útiles en el estándar (por lo que parece), como spor std::stringyi para la unidad imaginaria.

La cantidad de tiempo de codificación que los UDL guardarán en realidad no es tan alta, pero la legibilidad aumentará enormemente y cada vez más cálculos se pueden cambiar al tiempo de compilación para una ejecución más rápida.


Gracias por aclarar el punto sobre los espacios de nombres ... Me preguntaba eso.
Nathan Reed

12

Déjame agregar un poco de contexto. Para nuestro trabajo, los literales definidos por el usuario son muy necesarios. Trabajamos en MDE (Model-Driven Engineering). Queremos definir modelos y metamodelos en C ++. De hecho, implementamos una asignación de Ecore a C ++ ( EMF4CPP ).

El problema surge cuando se pueden definir elementos del modelo como clases en C ++. Estamos adoptando el enfoque de transformar el metamodelo (Ecore) en plantillas con argumentos. Los argumentos de la plantilla son las características estructurales de los tipos y clases. Por ejemplo, una clase con dos atributos int sería algo como:

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

Sin embargo, resulta que cada elemento en un modelo o metamodelo, generalmente tiene un nombre. Nos gustaría escribir:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

PERO, C ++, ni C ++ 0x no permiten esto, ya que las cadenas están prohibidas como argumentos para las plantillas. Puedes escribir el nombre char por char, pero esto es ciertamente un desastre. Con literales definidos por el usuario adecuados, podríamos escribir algo similar. Digamos que usamos "_n" para identificar nombres de elementos de modelo (no uso la sintaxis exacta, solo para hacer una idea):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

Finalmente, tener esas definiciones como plantillas nos ayuda mucho a diseñar algoritmos para atravesar los elementos del modelo, las transformaciones del modelo, etc. que son realmente eficientes, porque el compilador determina la información de tipo, identificación, transformaciones, etc. en tiempo de compilación.


44
Me gusta mucho la by the compiler at compile timeparte ... :-)
paercebal

12

Bjarne Stroustrup habla sobre los UDL en esta charla de C ++ 11 , en la primera sección sobre interfaces ricas en tipos, alrededor de 20 minutos.

Su argumento básico para UDL toma la forma de un silogismo:

  1. Los tipos "triviales", es decir, los tipos primitivos integrados, solo pueden detectar errores de tipo trivial. Las interfaces con tipos más ricos permiten que el sistema de tipos detecte más tipos de errores.

  2. Los tipos de errores de tipo que puede captar un código escrito de forma rica pueden tener un impacto en el código real. (Da el ejemplo del Mars Climate Orbiter, que falló infamemente debido a un error de dimensiones en una constante importante).

  3. En código real, las unidades rara vez se usan. La gente no los usa, porque incurrir en tiempo de ejecución o sobrecarga de memoria para crear tipos ricos es demasiado costoso, y usar un código de unidad con plantilla C ++ preexistente es tan feo que nadie lo usa. (Empíricamente, nadie lo usa, a pesar de que las bibliotecas han existido durante una década).

  4. Por lo tanto, para que los ingenieros usen unidades en código real, necesitábamos un dispositivo que (1) no incurre en gastos generales de tiempo de ejecución y (2) es notoriamente aceptable.


9

La verificación de dimensiones en tiempo de compilación es la única justificación requerida.

auto force = 2_N; 
auto dx = 2_m; 
auto energy = force * dx; 

assert(energy == 4_J); 

Véase, por ejemplo, PhysUnits-CT-Cpp11 , una pequeña biblioteca de solo encabezado C ++ 11, C ++ 14 para el análisis dimensional en tiempo de compilación y la manipulación y conversión de unidades / cantidades. Más simple que Boost.Units , admite literales de símbolos de unidad como m, g, s, prefijos métricos como m, k, M, solo depende de la biblioteca estándar de C ++, solo SI, potencias integrales de dimensiones.


O vea unidades , una biblioteca de conversión de unidades y análisis dimensional en tiempo de compilación, solo encabezado, construida en c ++ 14 sin dependencias de Nic Holthaus .
Martin Moene

6

Hmm ... todavía no he pensado en esta característica. Su muestra fue bien pensada y es ciertamente interesante. C ++ es muy poderoso como lo es ahora, pero desafortunadamente la sintaxis utilizada en los fragmentos de código que lee es a veces demasiado compleja. La legibilidad es, si no toda, al menos mucho. Y tal característica estaría orientada a una mayor legibilidad. Si tomo tu último ejemplo

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... Me pregunto cómo expresarías eso hoy. Tendría una clase KG y una clase LB y compararía los objetos implícitos:

assert(KG(1.0f) == LB(2.2f));

Y eso también funcionaría. Con tipos que tienen nombres más largos o tipos que no tiene esperanzas de tener un buen constructor para escribir un adaptador, podría ser una buena adición para la creación e inicialización de objetos implícitos sobre la marcha. Por otro lado, también puede crear e inicializar objetos utilizando métodos.

Pero estoy de acuerdo con Nils en matemáticas. Las funciones de trigonometría C y C ++, por ejemplo, requieren entrada en radianes. Sin embargo, pienso en grados, por lo que una conversión implícita muy corta como la publicada por Nils es muy buena.

Sin embargo, en última instancia, será azúcar sintáctico, pero tendrá un ligero efecto sobre la legibilidad. Y probablemente también será más fácil escribir algunas expresiones (sin (180.0deg) es más fácil de escribir que sin (deg (180.0)). Y luego habrá personas que abusen del concepto. Pero entonces, las personas que abusan del lenguaje deberían usar lenguajes muy restrictivos en lugar de algo tan expresivo como C ++.

Ah, mi publicación dice básicamente nada, excepto: todo va a estar bien, el impacto no será demasiado grande. No nos preocupemos. :-)


55
¡Tus paréntesis están desequilibrados! Lo siento, mi TOC también me odia.
X-Istence

3

Nunca he necesitado o deseado esta función (pero este podría ser el efecto Blub ). Mi reacción instintiva es que es poco convincente y es probable que atraiga a las mismas personas que piensan que es genial sobrecargar a operator + para cualquier operación que pueda interpretarse remotamente como una adición.


Confirmo: artículo muy interesante.
paercebal

2

C ++ suele ser muy estricto con respecto a la sintaxis utilizada: salvo el preprocesador, no hay mucho que pueda usar para definir una sintaxis / gramática personalizada. Por ejemplo, podemos sobrecargar los operadores existentes, pero no podemos definir los nuevos. En mi opinión, esto está muy en sintonía con el espíritu de C ++.

No me importan algunas formas de código fuente más personalizado, pero el punto elegido me parece muy aislado, lo que me confunde más.

Incluso el uso previsto puede hacer que sea mucho más difícil leer el código fuente: una sola letra puede tener efectos secundarios de gran alcance que de ninguna manera se pueden identificar desde el contexto. Con simetría para u, l y f, la mayoría de los desarrolladores elegirán letras simples.

Esto también puede convertir el alcance en un problema, el uso de letras individuales en el espacio de nombres global probablemente se considerará una mala práctica, y las herramientas que supuestamente mezclan bibliotecas más fácilmente (espacios de nombres e identificadores descriptivos) probablemente anularán su propósito.

Veo algo de mérito en combinación con "auto", también en combinación con una biblioteca de unidades como unidades de impulso , pero no lo suficiente como para merecer esta adición.

Sin embargo, me pregunto qué ideas inteligentes se nos ocurren.


1
using single letters in global namespace will probably be considered bad practicePero eso no tiene relevancia: (A) Los UDL deben definirse en el ámbito del espacio de nombres (no global) ... presumiblemente porque (B) deben consistir en un guión bajo y luego> = 1 letra, no solo la letra, y dichos identificadores en los NS globales están reservados para la implementación. Eso es al menos 2 puntos en contra de la idea de que los UDL generan confusión de forma innata. En cuanto a tener que abarcar el espacio de nombres que reduce la utilidad de la función, es por eso que stdlib los declara en inline namespaces que los usuarios pueden importar al por mayor si lo desean.
underscore_d

2

Usé literales de usuario para cadenas binarias como esta:

 "asd\0\0\0\1"_b

utilizando std::string(str, n)constructor para que\0 no corte la cadena por la mitad. (El proyecto hace mucho trabajo con varios formatos de archivo).

Esto fue útil también cuando abandoné std::stringa favor de un contenedor para std::vector.


-5

El ruido de línea en esa cosa es enorme. También es horrible de leer.

Déjame saber, ¿razonaron esa nueva adición de sintaxis con algún tipo de ejemplos? Por ejemplo, ¿tienen un par de programas que ya usan C ++ 0x?

Para mí, esta parte:

auto val = 3.14_i

No justifica esta parte:

std::complex<double> operator ""_i(long double d) // cooked form
{ 
    return std::complex(0, d);
}

Ni siquiera si usarías la sintaxis i en otras 1000 líneas también. Si escribe, probablemente también escriba 10000 líneas de algo más a lo largo de eso. Especialmente cuando probablemente escribirás sobre todo en todas partes esto:

std::complex<double> val = 3.14i

Sin embargo, la palabra clave 'auto' puede estar justificada, solo tal vez. Pero tomemos solo C ++, porque es mejor que C ++ 0x en este aspecto.

std::complex<double> val = std::complex(0, 3.14);

Es como ... así de simple. Incluso aunque todos los soportes estándar y puntiagudos sean poco convincentes si los usas en todas partes. No empiezo a adivinar qué sintaxis hay en C ++ 0x para convertir std :: complex en complex.

complex = std::complex<double>;

Tal vez sea algo sencillo, pero no creo que sea tan simple en C ++ 0x.

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

¿Quizás? > :)

De todos modos, el punto es: escribir 3.14i en lugar de std :: complex (0, 3.14); en general no le ahorra mucho tiempo, excepto en algunos casos súper especiales.


10
@Cheery: Para usted, "auto val = 3.14i" no justifica el código escrito para admitirlo. Podría responder eso, para mí "printf ("% i ", 25)" no justifica el código escrito para printf. ¿Ves un patrón?
paercebal

55
@Cheery: "El ruido de línea en esa cosa es enorme". No, no lo es ... "También es horrible leer". Su argumento subjetivo es interesante, pero debería echar un vistazo a la sobrecarga del operador en general para ver que el código de esta característica está lejos de ser sorprendente / impactante ... Para un desarrollador de C ++
paercebal

3
auto ayudará a la legibilidad. considere usar interadores en un bucle for: for (auto it = vec.begin (); it! = vec.end (); ++ it) ... Sé sobre for_each, pero no me gusta tener que crear un functor para usarlo .
KitsuneYMG

1
@kts: Con C ++ 1x tendremos lambda y rango para
Joe D

3
Si su línea de C ++ es mejor que C ++ 0x, entonces mi línea es mejor todavía. Escribir simplemente: std::complex<double> val(0, 3.14);.
Ben Voigt
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.