En este artículo quiero proponer una manera eficaz y general de suprimir una advertencia de “parámetro sin referencia” en los programas de C++. Tras explicar varias soluciones estándar, propongo la solución de la función fantasma.

Introducción

Si uno quiere programar con buen estilo, entonces suele activar el máximo nivel de advertencia del compilador. Esto, por cierto, también es una ayuda para entender bien el concepto de lenguaje. Dejarse advertir sobre todo puede resultar en que no todas las advertencias aciertan. Sin embargo, desactivarlas a coste de no ser advertido por errores significativos tampoco conviene.

Por ejemplo, si compilamos con Microsoft Visual Studio el constructor de copia

Object(const Object& source) {}

entonces se obtiene la siguiente advertencia: warning C4100: ‘source’ : parámetro formal sin referencia. Esto sería un caso típico de un constructor de copia que realmente no copia nada. Debemos mantener la interfaz para que no deje de ser un constructor de copia, pero actualmente no usamos el parámetro source.

Eliminar el parámetro

El artículo Visual C++: Warning C4100 discuta varias opciones que mencionamos aquí

  • Hacer caso a la advertencia y eliminar el parámetro no usado.
  • Si necesitamos el parámetro pero estamos seguros que no lo usaremos, entonces podemos quitar el nombre. Un constructor de copiar se quedaría sin “source”

    Object(const Object&) {}
    
  • Si queremos mantener el nombre aunque actualmente no lo usamos, podemos comentarlo.

    Object(const Object& /* source */) {}
    

    Debemos tener en cuenta que el comando @param de un comentario de documentación como lo usuaría Doxygen se quedría obsoleto. Deberíamos comentar el comantario. Además, los comentarios /* */ no suelen poder anidarse – un problema a la hora de deshabilitar bloques de código.

  • Deshabilitar la advertencia. En Microsoft Visual Studio esto se puede conseguir de la siguiente manera:

    #pragma warning( push )
    #pragma warning( disable: 4100 )
    Object(const Object& source) {}
    #pragma warning( pop )
    

    El problema de este enfoque es que se necesita una directiva #pragma diferente para cada compilador y ni siquiera está garantizado que haya. Así no conviene si el programa debe compilar en varias plataformas.

Una macro de “parámetro no referenciado”

A parte de estas propuestas suele haber otro apaño de usar el parámetro. Por ejemplo

Object(const Object& source)
{
    source = source;
}

Por ser una construcción no especialmente obvia, se puede crear una macro UNREFERENCED_PARAMETER.

#define UNREFERENCED_PARAMETER(param) param = param
Object(const Object& source)
{
    UNREFERENCED_PARAMETER(source);
}

La macro trae la ventaja que se puede definir de forma diferente según el efecto deseado. Una versión de release podría expandir la macro a nada:

#ifdef _DEBUG
#define UNREFERENCED_PARAMETER(param) param = param
#else
#define UNREFERENCED_PARAMETER(param)
#endif

Lógicamente volvería salir la advertencia cuando la macro suprime el uso del parámetro.

La desventaja de la asignación es tiempo de cálculo que requiere y que no está disponible en todas las clases. Estas clases son qquellas que tienen el operador = sobrecargado, pero ninguna sobrecarga admite una instancia de la clase misma como parámetro (o fuente) de la asignación.

Función fantasma

Mi forma preferida es una mezcla de varias propuestas y usa una función fantásma.

// La función fantásma (dummy function)
inline void reference_parameter(const void*) { }

// La macro
#define UNREFERENCED_PARAMETER(param) \
    reference_parameter(static_cast<const void*>((&param)));

// El uso
Object(const Object& source)
{
    UNREFERENCED_PARAMETER(source);
}

Esta propuesta reune todas las ventajas.

  • Gracias a referenciar el parámetro no referenciado por una macro, podemos eliminar y cambiar esta definición sin tocar el resto del código.
  • Si dejamos la macro como aquí propuesta, entonces se reemplaza por una llamada a una función con un puntero al parámetro no usado. Esta operación siempre es posible con cualquier objeto.
  • La función reference_parameter no pone nombre al parámetro, por lo cual no aparece una advertencia de “parámetro sin referencia”.
  • Finalmente es una operación rápida. Copiar un puntero es rápido y como la función no hace nada, desaparecerá con la expansión inline.

Referencias

Enlaces externos
En este sitio

Lectura adicional


Anuncios