Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Loretz

#51

struct s {
private:
int x = 0;
public:
s(int _x) : x{ _x } {}              //  converting constructor: inicializa un s a partir de un int
void p() const { std::cout << x; }
int getx() const { return x; }
};


Estas cuatro expresiones hacen exactamente lo mismo: invocan al "converting constructor".

s _s(5);      // crea _s a partir del int 5   
s _t = 6;      // crea _t a partir del int 6
s _u{ 7 };     // crea _u a partir del int 7 (direct-list-initialization a partir de C++11)
s _v = { 8 }; // crea _v a partir del int 8 (copy-list-initialization a partir de C++11)


En este caso las cuatro expresiones construyen e inicializan un objeto de tipo 's' a través del "converting constructor", que es el constructor que especifica la conversión desde el tipo int al tipo s.

En C++98 sólo existían las dos primeras y C++11 introduce las dos últimas, que las llama "uniform initialization", en sus dos variantes, "direct list initialization" y "copy list initialization".

Si observas la salida del programa, se mostrarán los ints 5, 6, 7, y 8 porque esos son los valores con que cada objeto fue inicializado.

Y Si usas el debugger para ejecutar paso a paso el programa, verás que cómo el flujo de ejecución pasa por ese constructor.
#52
Programación C/C++ / Re: que editor usan
22 Junio 2019, 02:04 AM
En Windows, Visual Studio y C++Builder; en Linux, Oracle Developer Studio (si puedo elegir)
#53

El que se mete con uno se está metiendo con todos...

https://en.cppreference.com/w/cpp/language/rule_of_three

Además:
Un comentario y un error:

El comentario es que cuando dices:
double getd() const { return *this->d; }
no necesitas aclarar que se trata del miembro 'd' de 'this', de eso no hay dudas. El puntero this se usa en las expresiones cuando es *realmente* necesario, por ejemplo, para salvar alguna ambigüedad (necesario), o porque los nombres de los miembros y parámetros ya han hecho un lío tal que no se sabe quién es quién (un parche que suele usarse para dejar en claro situaciones como "el lío este yo no lo hice así que ahora aguantarse el this").

Y el error:
getd() devuelve *d, y el problema aquí es que *d no fue inicializado, no se le asignó un valor; y pretender acceder en modo lectura (cuando haces s2 = s0 + s1;) a una variable sin inicializar es lo que el estándar define como "Undefined Behavior", que significa que puede suceder cualquier cosa (normalmente mala).



#54
Citar... tiempo de compilacion... mientras escribes el código o haces el build? ...

static_assert como dices, es una comprobación "en tiempo de compilación". Si el compilador detecta una contradicción al evaluar el static_assert suspenderá la compilación (y emitirá el mensaje de error optativo).

Pero... ¿por qué el Visual Studio (y otros IDEs) muestran una marca de error antes de compilar?

Para el caso del editor de código del Visual Studio la herramienta se llama IntelliSense https://docs.microsoft.com/en-us/visualstudio/ide/using-intellisense?view=vs-2019, que entre otras cosas, es la que señala errores con una linea roja y sinuosa (error squiggle), como cuando escribes en un editor de texto con faltas de hortografía.

Este tipo de herramientas (error squiggle, code-completion, symbol searching, go to definition, ...) son muy difíciles de implementar en C++, y durante años han sido una pesadilla para muchos fabricantes de IDEs (y lo son aún), así que no hay que asustarse si alguna vez falla. Imagina un proyecto que demora en compilar 20 minutos, pero el error-squiggle se muestra instantáneamente con cada tecla pulsada.

#55
Si lo que necesitas es saber si está activo el bit 6 o el 7, pero no ambos a la vez, y no te importa cual de los dos, siempre que sea uno y solo uno de ellos el que esté activo, podrías hacer:

[EDITO:]
   unsigned var = 182;         // 1011 0110
   unsigned mask6 = 0x40;      // 0100 0000
   unsigned mask7 = 0x80;      // 1000 0000

   bool res = (var & mask6 || var & mask7) && !(var & mask6 && var & mask7);


En C++ puedes usar std::bitset también, que es más fácil para todos.
#56
Nada nuevo que aportar al tema, sólo una noticia, que creo que puede servir para los que nos hemos interesado en este tema de las constexpr, y también creo que puede servir para ir formándonos una idea acerca del C++ de hoy y ayudar a poner algunas cosas en perspectiva.

La Noticia:
Del 15 al 20 de septiembre, presentado por la Standard C++ Fundation, Jason Turner va a dar una conferencia sobre "Applied `constexpr`: Doing More Work At Compile Time" https://cppcon.org/class-2019-constexpr/

Registrarse "full" después del 6 va a costar 1500 dólares, pero hay descuentos... (no es que sea muy barato, pero full incluye los sanguchitos y una camiseta alegórica)  ;D

Aviso que no estoy invitado, pero de todos modos me gusta saber que hay un mundo más allá de los char* que sigue orbitando alrededor del Sol, aunque no lo veamos.


#57
Disculpas si me paso de consejista ("consejista": opinólogo aconsejador), pero creo que no conviene mezclar demasiados temas a la vez. Si estás viendo el concepto de "constant expressions" creo que conviene concentrarse en qué es const y qué es constexpr, sus definiciones, significados, ejemplos de uso, pero no mucho más, y dejar (con pesar, claro), los detalles más finos para más adelante.

Porque como vemos, se nos mezclan temas más complejos que en lugar de ayudar a aclara las cosas las oscurecen bastante. Ejemplo: no sólo están los conceptos complejos (nada simples) que concurren en cualquier tema que se mire, además si seguimos todos los links que encontremos no vamos a perder como Hansel y Gretel. Y encima hasta tenemos la suerte de encontrarnos con que algunos compiladores de comportan de una manera y otros de otra.

[Nota]Este último punto, eso de que algunos compiladores se comportan de una manera y otros de otra, suele suceder cuando hacemos algo muy mal y el compilador tiene permiso para hacer lo que quiera con eso. En el estándar se denomina "Undefinded Behavior", comportamiento indefinido. Pero ¿cómo es que con algo aparentemente tan simple podemos hacer las cosas tan mal? Porque no es cierto que sea simple, acá no hay nada simple, lo simple ya se acabó hace mucho. Los temas se presenta más o menos simples para que podamos empezar a hacer algo útil sin asustarnos, pero no es cierto que sean simples, cualquier cosa, la más inocentes de las oraciones, esconde un mundo bastante complejo, como en la vida.[/Nota]

Pero volviendo a lo nuestro...

CitarEn la línea 11, tienes int x;, pero no esta inicializado, que valor se le pasara a la función ?

Yo sé la respuesta, pero como la pregunta va dirigida a RayR...

CitarAh!!.. ya vi el por que, pasa que en C++11 las funciones constexpr solo pueden retornar valores (o expresiones) constantes, no variables...

Las funciones no devuelven variables; las funciones devuelven valores, "if any". https://en.cppreference.com/w/cpp/language/return

En el caso de funciones declaradas constexpr, en el estándar C++11 sólo se permitía que el cuerpo de la función tuviera una sola línea con el return. En C++14 se permite más de una línea. Ejemplo:

Código (cpp) [Seleccionar]
constexpr int fun_cpp14(int a) // C++14 permite dos o mas lineas; siempre devuelve un valor.
{
    int i = a + 5;
    return i;
}

constexpr int fun_cpp11(int a) // C++11 solo permite una linea con el "return"
{
    return a + 5;
}


Funcionalmente no ha cambiado nada, es un poco más cómodo nada más. Para más detalles puedes consultar en "la documentación" [Copy elision] https://en.cppreference.com/w/cpp/language/copy_elision

Pero, fíjate un poco en lo que decía más arriba, ¿hasta dónde conviene fijarse en los detalles? O mejor dicho, ¿es ahora que me conviene meterme con esos detalles? Para entender ese artículo se necesita también entender qué es un prvalue (value semantics), y tener muy claro eso de los copy y move constructors, por supuesto, pero por suerte aclara que esos constructores no necesitan estar presentes ni accesibles. Buena aclaración, porque eso es así a partir del C++17... Y así todo. Por eso como consejólogo profesional, yo te diría que conviene ser metódico y paciente; cada oración tiene una densidad de plomo. Aquí ya no quedan inocentes, se los han comido a todos.

#58
CitarVi otra cosa respecto a constexpr respecto a int vs double y float..

Está bien eh.

No tengo una cita del estándar que sirva de documento, pero creo que...

const int tiene un estátus especial que no tienen los demás.

En el primer caso, por qué esto no da problemas?
//esto no da problemas:
const int ix = 7;
constexpr double dx = 520.5 * ix;


Desde antes de que se inventara constexpr (antes del C++11) un const int siempre tuvo un valor constante conocido en tiempo de compilación (siempre fue una "const expression"); por ejemplo cuando se usa como dimensión de un array:
    const int ix = 7;
    int array_ix[ix];


-- Nota: algunos compiladores (gcc, por ejemplo) incluyen una extensión al lenguaje que permite usar un int no constante como dimensión de un array ("variable length arrays"), pero es una extensión particular, fuera del estándar.

Pero no sucede lo mismo con floats o doubles, al menos no cuando se compila con el gcc. ¿Por qué? No sé. No lo sé, y sospecho que la respuesta no debe ser de las más simples, sobre todo porque los distintos compiladores tampoco se han puesto de acuerdo en esto.

Puse como ejemplo una versión más simple en Compiler explorer ( https://godbolt.org/z/sQ9BHB )

int main()
{
    //esto no da problemas:
    const int ix = 7;
    constexpr int ci = ix;

    //pero esto si los da:
    const float fx = 7.0;
    constexpr float cf = fx;

    //esto tambien da problemas:
    const double dx = 7;
    constexpr double cd = dx;

}



  • Para gcc está mal (puedes ver la lista de errores en el Compiler Explorer)
  • Para clang también está mal.
  • Para icc está bien.
  • para msvc también está bien.

Bueno, si alguien sabe algo más, que nos cuente.

#59
Jé, siempre conviene ser precavido con las recomendaciones de uno de por aquí...


Constexpr
¿Para qué sirve?


Tomado de los que dice Stroustrup en la "Part 1 - Introductory Material, Section 2.2.3 - Constants":

const es una promesa que uno le hace al compilador, dice que uno no va a tratar de modificar lo que declaró const, y el compilador lo cree.

constexpr sirve para que la expresión se evalúe (se asigne, se calcule) cuando se está compilando, y no cuando se ejecuta el programa.

Se usa principalmente para especificar constantes, para permitir ubicar datos en memoria donde sea difícil que vayan a corromperse, y también por razones de rendimiento (performance).
... (etcétera) ...

En esa sección pone varios ejemplos, y me voy a tomar el atrevimiento de agregar un par de comentarios como llamadas al pie:

Citarconst int dmv = 17; // dmv is a named constant --> (1)
int var = 17; // var is not a constant
constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression --> (2)
constexpr double max2 = 1.4*square(var); // error : var is not a constant expression
const double max3 = 1.4*square(var); // OK, may be evaluated at run time
double sum(const vector<double>&); // sum will not modify its argument
vector<double> v {1.2, 3.4, 4.5}; // v is not a constant
const double s1 = sum(v); // OK: evaluated at run time --> (3)
constexpr double s2 = sum(v); // error : sum(v) not constant expression

(1) Muy probablemente el compilador decida poner a dmv en un sector de memoria de sólo lectura, pero no está obligado.
(2) Dice que max1 podrá ser constexpr siempre que la función square() también lo sea.
(3) acá se declara a s1 como const, pero se va a calcular en el runtime (cuando se ejecuta el programa). La promesa es que una vez inicializado no se va a modificar.

¿Pero cómo es eso de hay funciones constexpr?
Más abajo lo aclara:
Para que una función pueda usarse en una contant expression tiene que estar definida como constexpr; ejemplo:

Citarconstexpr double square(double x) { return x*x; } // ajá!

quiere decir que si se le pasa un double declarado como constexpr, la función square también puede usarse en otras declaraciones constexpr.

¿Y en dónde está la gracia?
en que toda la expresión se va a evaluar (calcular) "at compile time", mientras se compila, así que va a tardar un poquito más el compilador pero después el ejecutable no va a tener que hacer nada; la llamada a función, la operación, el valor devuelto, la asignación, nada de eso va a ser necesario.



- Después, en la "Part 2 - Basic Facilities, Section 10.4 - Constant Expressions" se extinde un poco en este concepto. Pero después, ahora no hay apuro.


También, como referencia, siempre está "la documentación"
https://en.cppreference.com/w/cpp/language/constexpr

#60
También puedes usar un array de variants; en tu caso podría ser:

Código (cpp) [Seleccionar]
#include <iostream>
#include <array>
#include <algorithm>
#include <variant>

using namespace std;
using MiArray = std::array<std::variant<int, char>, 10>;

auto PrintMiArray = [](auto&& i)
{
    std::cout << "Encontrado: " << i << '\n';
};


template<typename T>
void BuscarEnElArray(MiArray miArray, T CosaAbuscar)
{
    MiArray::iterator found = find(miArray.begin(), miArray.end(), std::variant<int,char>(CosaAbuscar));
    if (found != miArray.end()) {
        std::visit(PrintMiArray, *found);
    }
    else {
        std::cout << CosaAbuscar << " no encontrado\n";
    }
}


MiArray primerArray = { 0,1,2,3,4,5,'a',6,7,8 };

int main()
{
    BuscarEnElArray(primerArray, 'a');
    return 0;
}