ProgrammationDéveloppeur C++, Développeur senior

Comment fonctionnent les templates de fonctions et de classes avec des paramètres par défaut ? Quelles subtilités d'utilisation existent et que faire en cas de conflits entre les fonctions templates et non-templates ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Les templates avec des paramètres par défaut sont un puissant mécanisme de programmation généralisée en C++.

Historique de la question :

La bibliothèque STL a commencé avec des templates. Plus tard, la possibilité de spécifier des valeurs par défaut pour les paramètres tant des fonctions templates que des classes a été introduite pour rendre les templates plus universels et soutenir l'extensibilité du code.

Problème :

Des conflits non évidents peuvent survenir lorsqu'il existe des surcharges de fonctions normales et de templates, ainsi que des ambiguïtés lors des spécialisations. Les paramètres par défaut dans les templates peuvent accroître la flexibilité, mais entraînent souvent des erreurs de compilation confuses.

Solution :

Il est préférable de minimiser le nombre de valeurs par défaut dans les templates, surtout s'il y a un croisement avec les versions non-templates. La priorité lors de l'appel de fonctions préfère une correspondance exacte avec une fonction normale plutôt qu'une template.

Exemple de code :

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

L'appel multiply(5, 4) choisira la fonction int multiply(int, int), tandis que l'appel multiply<>(5) invoquera le template et b prendra la valeur 2.

Caractéristiques clés :

  • Les valeurs par défaut ne sont déclarées que dans la première déclaration/définition du template.
  • Les fonctions classiques ont priorité sur les templates en cas de correspondance de signatures.
  • Les valeurs par défaut pour les paramètres des templates ne s'appliquent que lorsqu'elles sont absentes dans l'appel explicite.

Questions pièges.

Peut-on déclarer des paramètres par défaut dans une nouvelle définition d'une fonction template ?

Non, une valeur par défaut ne peut être spécifiée qu'à un seul endroit (généralement dans la déclaration), sinon il y aura une erreur de compilation.

Que se passe-t-il en cas d'ambiguïté entre un template et une fonction non-template ? Comment le compilateur choisit-il quoi appeler ?

Le compilateur privilégie toujours la fonction non-template si elle correspond exactement aux arguments. La template ne sera appelée qu'en l'absence d'une correspondance exacte.

Peut-on spécifier des valeurs par défaut pour un paramètre qui n'est pas de type template (par exemple, pour un entier) ?

Oui, par exemple :

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

Erreurs typiques et anti-patterns

  • Déclaration de valeurs par défaut simultanément à plusieurs endroits.
  • Ambiguïté implicite entre fonctions templates et normales.
  • Utilisation excessive de paramètres par défaut, rendant la lecture et le débogage du code difficiles.

Exemple de la vie réelle

Cas négatif

Une fonction template et une fonction non-template sont déclarées avec des paramètres et des valeurs par défaut correspondants. Dans un module, l'appel fonctionne comme prévu, mais dans un autre, une version inattendue de la fonction est choisie.

Avantages :

  • Pratique à appeler sans spécifier le type.

Inconvénients :

  • Erreurs non évidentes et logique d'appel complexe.

Cas positif

Pour des configurations qui se chevauchent, des noms différents sont déclarés explicitement pour les fonctions templates et non-templates, avec des valeurs par défaut présentes uniquement dans une des versions.

Avantages :

  • Comportement explicite.
  • Pas de collisions d'appel.

Inconvénients :

  • Un peu plus de code lors de la maintenance des versions de la fonction.