ProgramaciónDesarrollador C++, Desarrollador principal

¿Cómo funcionan las plantillas de funciones y clases con parámetros por defecto? ¿Cuáles son los detalles de su uso y qué hacer en caso de contradicciones entre funciones plantillas y no plantillas?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Las plantillas con parámetros por defecto son un mecanismo potente de programación genérica en C++.

Historia del tema:

Las plantillas fueron el punto de partida de la biblioteca STL. Más tarde, se introdujo la posibilidad de especificar valores por defecto para los parámetros de funciones y clases plantilla, con el fin de hacer las plantillas más universales y mantener la extensibilidad del código.

Problema:

Pueden surgir conflictos poco evidentes cuando hay sobrecargas de funciones normales y plantillas, así como ambigüedades en las especializaciones. Los parámetros por defecto en las plantillas pueden aumentar la flexibilidad, pero a menudo conducen a errores de compilación confusos.

Solución:

Es mejor minimizar el número de valores por defecto en las plantillas, especialmente si hay intersecciones con las versiones no plantilla. En la llamada a funciones, se prefiere una coincidencia exacta con la función normal en lugar de la plantilla.

Ejemplo de código:

template<typename T = int> T multiply(T a, T b = T(2)) { return a * b; } int multiply(int a, int b) { return a + b; }

La llamada multiply(5, 4) elegirá la función int multiply(int, int), mientras que la llamada multiply<>(5) invocará la plantilla, y b tomará el valor 2.

Características clave:

  • Los valores por defecto se declaran solo en la primera declaración/definición de la plantilla.
  • Las funciones normales tienen prioridad sobre las plantillas cuando las firmas coinciden.
  • Los valores por defecto para los parámetros de las plantillas se aplican solo en su ausencia en la llamada explícita.

Preguntas engañosas.

¿Se pueden declarar parámetros por defecto en una nueva definición de una función plantilla?

No, el valor por defecto solo se puede especificar en un lugar (generalmente en la declaración), de lo contrario habrá un error de compilación.

¿Qué sucede ante una ambigüedad entre una plantilla y una función no plantilla? ¿Cómo elige el compilador qué invocar?

El compilador siempre dará preferencia a la función no plantilla si se ajusta exactamente a los argumentos. La plantilla solo se invocará si no hay coincidencia exacta.

¿Se pueden especificar valores por defecto para parámetros que no son tipos de parámetro de plantilla (por ejemplo, para números)?

Sí, por ejemplo:

template<typename T, int N = 8> class Array { T data[N]; };

Errores típicos y anti-patrones

  • Declarar valores por defecto al mismo tiempo en varios lugares.
  • Ambigüedad implícita entre funciones plantilla y normales.
  • Uso excesivo de parámetros por defecto, lo que dificulta la lectura y depuración del código.

Ejemplo de la vida

Caso negativo

Se han declarado tanto una función plantilla como una no plantilla con parámetros coincidentes y valores por defecto. En un módulo, la llamada funciona como se esperaba, mientras que en otro se elige inesperadamente la versión incorrecta de la función.

Pros:

  • Conveniente invocar sin precisar el tipo.

Contras:

  • Errores poco evidentes y lógica de llamada confusa.

Caso positivo

Para configuraciones que se intersectan, se han declarado nombramientos diferentes y explícitos para las funciones plantilla y no plantilla, con valores por defecto solo en una de las versiones.

Pros:

  • Comportamiento explícito.
  • Sin colisiones en la llamada.

Contras:

  • Un poco más de código al mantener las versiones de la función.