Pasar distintos tipos de variables a una funcion sin tener eso en cuenta (solved

Hice una funcion con un solo parametro y en esa funcion se modifica y lo devuelve.
Tengo dos problemas, el primero es que no quiero hacer tres funciones distintas para tres tipos de variables diferentes, es decir algo asi

float funcion(float dato)
{
la procesa y devuelve float
return dato;
}
----
unsigned int funcion(unsigned int dato)
{
procesa igual pero con algunas pequeñas diferencias al ser sin signo y int
return dato
}

Necesitaria dos cosas:
Una poder pasar a la funcion el dato como un parametro sin que este definido el tipo, y la otra, que la funcion detecte el tipo de variable para poder trabajar con ella de forma distinta en funcion de eso.

No se si se podria hacer con un puntero para pasar por referencia el dato sin tener en cuenta el tipo, pero tampoco se como podria la función detectar si es un int , un unsigned int ....un float etc.

Podeis ayudarme en esto, estaría muy agradecido

Hi,
Podrias usar la instruccion switch.

C++ es de “tIpado fuerte” así que no lograrás lo que deseas si no pasas la variable convertida previamente

Lo ideal es un objeto con varios constructores no una función

Me pusiste a recordar C.

Quizás debas pasas una unión (si, unión, no estructura), que es la manera en que en C se podían hacer funciones con cierto polimorfirmo, pero es una barbaridad hoy en día, es mejor una clase que funcione sin necesidad de instanciar y que devuelva a través de un método adecuado, porque el retorno también va a estar tipado

Donde dije Digo, digo Diego

Me disculpo, soy más de Python que de C++ y tiendo a resolver con objetos siempre

Si puedes, necesitas usar templates, se me habían olvidado, ahora salí un momento a comprar comida a los perros y se me despejó la mente.

Tienes un gran ejemplo de uso te templates en una librería del maestro Luis Llamas

Por cierto, tiene un error el ejemplo de ordenación de enteros, creo que es a propósito (ya que tiempo atrás no lo tenía) y creo que, como todo profesor (y estoy seguro que Luis es profe también), aveces dejamos pequeños errores para que el estudiante aprenda criticidad y a acostumbrarse que no siempre copiar y pegar funciona.

No te voy a decir por aquí el error por respeto a Luis (estoy convencido que lo ha hecho por esa razón), si tienes problemas con el ejemplo int te lo digo por mensaje privado

A ver os explico un poco mas, porque no veo claridad.
La funcion a que hago referencia pertenece a una clase ya por si misma, de hecho es parte de una libreria que hace un teclado virtual de una pantalla TFT y que estoy escribiendo.
La idea es esa , y de hecho ya esta escrita y funciona, pero es poco elegante, o asi lo veo yo.
Al teclado se le llama para introducir un dato, y este puede ser un int, un unsigned, un float.....
Si a la funcion de la clase que hace toda la introduccion del dato lo que se le pide que devuelva es un float, debera dejar activa la tecla de "," y la de "-". si es un unsigned int estas teclas deberan estar bloqueadas. Y esa es la cuestion. Ademas debera devolver un float si se le paso un float,.
No subo la libreria completa porque no esta rematada y ademas necesitaria una pantalla TFT para probarla., Como os digo funciona, pero no me gusta como esta escrita esta funcion en particular.
Si lo veis necesario os la subo aqui y le echais un vistazo.
Es un codigo bastante largo. Cuando este terminada subire todas las librerias, Son objetos virtuales para un HMI para las pantallas tft que uso. Son simples de usar pero al menos para mi complejas de escribir si se quieren hacer bien. No me gustan los errores y soy un poco maniatico en eso.
Hay leds virtuales, visualizadores de datos tipo digital, barra de medida, tipo voltimetro de aguja, ...........Todo eso esta hecho y funciona a falta de terminar de pulir.
Ahora estoy con la intruduccion de datos ...y para eso es el teclado virtual.
Gracias de nuevo

Una clase es la respuesta

No cabe en la respuesta todo el codigo de la funcion, si por favor me indicais como pegarla…tiene mas de 9000 caracteres.

A la funcion le paso los siguientes parametros

float TECLADO::teclado_dato(float dato,int tip_var ,int digitos)
{
......... codigo.......

...........final de la funcion.,,,,,,,,,,,,,,,,,,,,,,


            // TECLA ENTER

            if ((pixel_x > (pos_x + (t_t * 3))) && (pixel_x < (pos_x + (t_t * 4))) && (pixel_y > (pos_y + (t_t * 2))) && (pixel_y < (pos_y + (t_t * 4))))
            {
                // borra el numero de la pantalla del teclado

                _tft->fillRect(pos_x + 2, pos_y - 40, (t_t * 4) - 4, 36, TFT_BLACK);
                _tft->setFont(&FreeSans9pt7b);
                _tft->setTextSize(2);
                _tft->setCursor(pos_x + 15, pos_y + 30 - 42);
                _tft->print(0);

                coma = false;
                tecla_pulsada = 14;
                tecla(pos_x + (t_t * 3), pos_y + (t_t * 2), t_t, t_t * 2, "E", tipo, true, TFT_RED, texto_color);

                i = 0;
                if (tip_var > 3)
                    tip_var = 1;
                t_now = millis();
                if (tip_var == 1)
                {
                    float valor_f = atof(numero);
                    for (int j = 0; j < 10; j++)
                        numero[j] = ' ';
                    return valor_f;
                }
                if (tip_var == 2)
                {
                    int valor_ui = atoi(numero);
                    for (int j = 0; j < 10; j++)
                        numero[j] = ' ';
                    return valor_ui;
                }
                if (tip_var == 3)
                {
                    unsigned int valor_i = atoi(numero);
                    for (int j = 0; j < 10; j++)
                        numero[j] = ' ';
                    return valor_i;
                }
            }
        }
    }
    return dato;
}

Como se puede ver retorna el valor con distino tipo en funcion del parametro que le indica el tipo a devolver, aunque se le pase como float y la funcion de inicialice como devolviendo un float.
Funciona, pero no me parece que este bien programado.
Solo soy un aficionado y quizas es que no tengo los conocimientos suficientes,.
Mil gracias de nuevo

Claro que no funciona

Primero recibes los datos

float TECLADO::teclado_dato(float dato,int tip_var ,int digitos)
{

Donde recibes la variable float dato

haces muchas cosas y acabas con

  return dato;

Pero en medio con dato no haces nada

Luego tienes 700 returns por el medio, que es la mejor manera de perderse

Groso modo esto es lo que tienes que hacer

template <typename TIPO>

TIPO funcion(TIPO parametro){
    TIPO respuesta;

    <<<---- hacer muchas cosas --->

    // --- Por ejemplo
    restuesta = parametro + 25;


    <<<---- hacer muchas mas cosas --->

    if tal
        respuesta = parametro * 20;
    else porque no
        respuesta = respuesta + 15;
        // --- o respuesta += 15;

    <<<---- hacer muchas mas cosas --->


    return respuesta
}


// --- Voy a usarla


// --- Voy a usarla

entero1 = 10;
entero2 = funcion<int>(entero1);

float1 = 10.3f;
float2 = funcion<float>(float1);

Búscate información sobre templates en C++ para ampliar información

Mil gracias, no conocia lo de template, y pese a que lei lo del Sr Luis Llamas, que por cierto siempre aprendi mucho con ese Sr, no lo entendi.
Lo que me pones me lo deja muchisimo mas claro.
Comentar una cosa, dices que el paso de dato no hace nada, y efectivamente es asi, pero te explico la razon.
La funcion no interrumpe el programa en ningun momento, por lo que si testeo si se ha tocado el teclado y la funcion sale sin hacer nada lo que ocurre es que como es logico devuelve false o "0". En ese caso el valor a que igualo la salida de la funcion se pierde y se hace cero y eso no puede ser.
Por tanto si no se modifica dentro de la funcion, entra y sale en el mismo valor. Paso el dato en el parametro y lo devuelvo si no se ha hecho nada....y el programa no se ha interrumpido durante el testeo del teclado.
Voy a probar con lo que me dijiste y os comento ....seguro que funciona bien y es mucho mas elegante que lo que yo hago y ademas acabo de aprender algo que no sabia.
Mil gracias....

Usa siempre un sólo return, siempre, y una variable para cambiar el valor, es más visible

A ver, voy entendiendo y mejorando pero aun no lo tengo claro del todo. Te pego el codigo que modifico.
En el archivo de cabecera .h

class TECLADO
{
public:

	TECLADO(MCUFRIEND_kbv* prtTFT, TouchScreen* TouchScreen);
	
	void teclado(int x, int y, int tamano, uint16_t tc_color, uint16_t te_color, bool formato_teclado);
	template <typename TIPO>
	TIPO  teclado_dato(TIPO dato,int tip_var,int digitos);
	void borra_teclado(void);
......... mas codigo

En el .cpp

template <typename TIPO>

TIPO TECLADO::teclado_dato(TIPO dato,int tip_var ,int digitos)
{    
    TIPO salida;
    
    if (tecla_pulsada != 0)
    {
        if (millis() > (t_now + 300))
        {
            _tft->fillRect(pos_x + 2, pos_y - 40, (t_t * 4) - 4, 36, TFT_BLACK);
            _tft->setFont(&FreeSans9pt7b);
            _tft->setTextSize(2);
            _tft->setTextColor(TFT_WHITE);
            _tft->setCursor(pos_x + 15, pos_y + 30 - 42);
            _tft->print(numero);
--------------- mas codigo

y la utilizacion es lo que no veo como hacer…

Yo hago esto…

if (teclado_on) 
    {   // solicita al teclado un dato, de tipo float (tipo 1) y de 4 digitos
        dato_new = teclado_1.teclado_dato(dato_1,1,4);
        if (dato_1 != dato_new)
        {
            dato_1 = dato_new;
        }
    }

siendo data_new y dato float por ejemplo… o tambien podrian ser los dos int…

Cada vez seran de un tipo diferente segun donde llame yo la funcion en el programa principal

Como deberia hacer la llamada a la funcion en el codigo?
Esa es la duda que me queda…

EL compilador me devuelve esto

error linking for board ATmega2560 (Mega 2560) (Arduino Mega)
ccx2mXda.ltrans0.ltrans.o*: In function main
Build failed for project 'Ejemplo_teclado_MCUFRIEND'
 (.text.startup+0x27bc): undefined reference to float TECLADO::teclado_dato<float>(float, int, int)

aunque lo escriba asi me da el mismo error

dato_new = teclado_1.teclado_dato<float>(dato_1,1,4);

Sigo pensando en tu solución pero creo que aunque me serviría para pasar el tipo de dato que sea no me sirve para el funcionamiento que necesito. Me explico.
El teclado recoge las pulsaciones en un array de caracteres que luego convierto al tipo de dato que le he pedido, y lo hago con atoi() , atof()…lo clásico. Mira el código que pegue y veras que la función trabajaría pero seguiría sin saber el tipo de dato que le he pasado, no sabría a que tipo de dato convertirlo.
He probado a recompilar con el ultimo software de Arduino y sigue dándome el mismo fallo. Tambien he probado a escribir el código de distintas formas y sigue fallando al compilar con el mismo error.
Yo no uso el compilador de Arduino, trabajo con vmicro y Microsoft Studio, porque así uso el mismo entorno para otros lenguajes en que tambien trabajo, C#, C++, Visual C…

Ya lo que necesitas es aplicar nivel de abstracción, si programas en varios lenguajes, sabes a lo que me refiero, creo que hasta aquí es donde puedo ayudarte, un saludo

Muchas gracias por tu ayuda, seguiré mirando para ver porque da ese fallo el compilador y que solución es la mejor.

Nos cuentas cómo te ha ido

Sigue dandome errores el linkado

No entiendo porque este codigo no me da el error y el mio si.

void setup() {
  // put your setup code here, to run once:

}
int i;
float j;
unsigned long tiempo_old;

void loop() {
  // put your main code here, to run repeatedly:
dato(i,2000);
i++;
dato(j,1000);
}



template <typename tipo>
void dato(tipo& dat, int tiempo)
{
  if (millis() > (tiempo_old + tiempo))
  {
    Serial.print(dat);
    tiempo_old = millis();
  }
}

Ese codigo lo compila perfectamente

pero si compilo esto en el cpp

template <typename tipo>
void V_DATOS::dato(tipo& dat, int tiempo)
{
  if (millis() > (tiempo_old + tiempo))
  {
    tiempo_old = millis();
  }
}

declarandolo dentro de su clase en el .h asi

class V_DATOS
{
public:

 V_DATOS(MCUFRIEND_kbv* prtTFT, TouchScreen* TouchScreen,TECLADO* Teclado);

 void ventana(int x, int y, int tipo_variable,int num_digitos,int tipo_marco, uint16_t f_col, uint16_t t_col);

 template <typename tipo>
 void dato(tipo& dat, int tiempo);

 float introducir_dato(float dat);
 int introducir_dato(int dat);

private:

 int pos_x;
 int pos_y;
 int pixel_x;
 int pixel_y;
 int tamano_x, tamano_y;
 int tamano_letra;
 uint16_t f_color, t_color;
 int tip_var;
 int digitos;
 
 unsigned long tiempo_old;
 bool teclado_on;
 
 bool Touch_getXY(void);

protected:

 MCUFRIEND_kbv* _tft;  // nuevo denominacion del puntero para esta libreria    
 TouchScreen* _ts; // denminacion de puntero para la tactil
 TECLADO* _teclado;
 
};

me da error el linkado en la llamada a la funcion del programa de uso

ERROR

Compiling 'Ejemplo_Ventana_Datos_MCUFRIEND' for 'ATmega2560 (Mega 2560) (Arduino Mega)'

cc6kmpQU.ltrans0.ltrans.o*: In function main


Error linking for board ATmega2560 (Mega 2560) (Arduino Mega)
Build failed for project 'Ejemplo_Ventana_Datos_MCUFRIEND'
  (.text.startup+0xc08): undefined reference to void V_DATOS::dato<float>(float&, int)

collect2.exe*: error: ld returned 1 exit status

en el programa se usa asi

vent_datos_2.dato(dato_f,500);

Si lo declaro como float sin los template y demas compila bien y funciona bien…pero claro tengo que escribir yna rutina igual para cada tipo de dato

La funcion no hace nada, porque es solo para probar…

Lo que te está dando problemas es esto

MCUFRIEND_kbv* _tft;  // nuevo denominacion del puntero para esta libreria

De hecho, te indica claramente:

‘Ejemplo_Ventana_Datos_MCUFRIEND’ for 'ATmega2560 (M

¿Dónde has declarado el tipo de datos MCUFRIEND?
¿No te falta un include de una librería externa?

El fallo es en el puntero de la TFT?
Si quito la linea de uso del .ino ya no da el fallo de linkado y si compilo pero declarandolo todo como float y no como template… linka y funciona bien.
Si yo respeto lo escrito en el .h y en el cpp pero anulo esa linea del .ino el linker se lo traga bien. Por lo que no pensaba que el puntero a la tft tenga nada que ver. Mas bien en mi corto entendimiento dice que es por que no esta definida la funcion.
Es mas, si repito la llamada a la rutina en el ,ino con varios tipos de variables me da el error repetido con las indicaciones correspondientes…

Compiling 'Ejemplo_Ventana_Datos_MCUFRIEND' for 'ATmega2560 (Mega 2560) (Arduino Mega)'


Error linking for board ATmega2560 (Mega 2560) (Arduino Mega)
Build failed for project 'Ejemplo_Ventana_Datos_MCUFRIEND'

cczyMlTU.ltrans0.ltrans.o*: In function main
  (.text.startup+0xc08): undefined reference to void V_DATOS::dato<int>(int&, int)
  (.text.startup+0xc18): undefined reference to void V_DATOS::dato<float>(float&, int)

collect2.exe*: error: ld returned 1 exit status

Eso es poniendo dos llamadas a la funcion en el .ino con un int y un float…
Es el unico error que da…

No entiendo la razon. Ten en cuenta que soy un aficionado no estudie programacion, solo es como hobby, y tengo muchas lagunas…

Mil gracias de nuevo