Quiz Généricité (révision classe de M. Rentsch)
Qu'affiche le code suivant ? (En dehors des warnings de compilation)
#include <cstdlib>
#include <iostream>
using namespace std;
template <typename T>
T somme(T a, T b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.5;
cout << somme(a, a) << " " << somme(b, b) << " " << somme(a, b);
return EXIT_SUCCESS;
} Erreur de compilation
On change le code précédent comme ci-dessous. Quel est l'affichage ? (En dehors des warnings de compilation)
#include <cstdlib>
#include <iostream>
using namespace std;
template <typename T>
T somme(T a, T b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.5;
cout << somme<int>(a, b) << " " << somme<double>(a, b);
return EXIT_SUCCESS;
} 3 3.5
On change encore le code précédent (dans le main) comme ci-dessous. Entrez ce qu'affichera le programme.
#include <cstdlib>
#include <iostream>
using namespace std;
template <typename T>
T somme(T a, T b)
{
return a + b;
}
int main()
{
int a = 1;
char c = 'A'; // Le code ASCII de 'A' vaut 65
cout << somme<char>(c, a) << " " << somme<int>(c, a);
return EXIT_SUCCESS;
} B 66
La déduction des types permet de ne pas spécifier les valeurs de toutes les variables des templates si elles peuvent être déduites lors de l'appel. Elle s'applique ...
Seulement aux fonctions
Lors d'un appel de fonction, si une fonction ordinaire et une fonction générique peuvent convenir toutes les deux, laquelle des deux fonctions est choisie ?
La fonction ordinaire
Pour trouver quelle définition appliquer lors d'un appel de fonction, si plusieurs fonctions génériques conviennent (en examinant les paramètres de type), le compilateur choisit le patron le plus spécialisé s'il peut être déterminé.
Vrai
On peut avoir des paramètres génériques qui ne sont pas des types, i.e.
écrire par exemple, template<typename T, int n> pour :
Les deux
On considère le code suivant, qui compile. Qu'affiche-t-il ?
#include <cstdlib>
#include <iostream>
using namespace std;
template <typename T1, typename T2>
T1 somme(T1 a, T2 b)
{
return a + (T2)b;
}
template <typename T>
T somme(T a, T b)
{
return a + b + 1;
}
int main()
{
int a = 1;
double b = 2.5;
cout << somme(a, a) << " " << somme(b, b) << " " << somme(a, b) << " " << somme(b, a);
return EXIT_SUCCESS;
} 3 6 3 3.5
Le programme suivant ne compile pas. Quelle(s) ligne(s) n'est (ne sont) pas correcte(s) ?
1| #include <cstdlib>
2| #include <iostream>
3|
5| using namespace std;
6|
7| template <typename T, int n>
8| T somme(T a)
9| {
10| return a + n;
11| }
12|
13| int main()
14| {
15| int a = 1;
16|
17| cout << somme<>(a) << endl;
18| cout << somme<10>(a) << endl;
19| cout << somme<int, a>(a) << endl;
20| cout << somme<int, true>(a) << endl;
21|
22| return EXIT_SUCCESS;
23| } - La ligne 17
- La ligne 18
- La ligne 19
Ligne 17: Le paramètre n ne peut pas être déduit.
Ligne 18: Idem.
Ligne 19: La valeur de n doit être définie à la compilation, elle ne peut donc pas provenir d'une variable.
Ligne 20: true se convertit par promotion numérique en entier pour affecter n
On souhaite utiliser une classe nommée FractionGeneralisee, qui est définie ainsi:
template<typename T>
class FractionGeneralisee {
T num;
T den;
public:
FractionGeneralisee(T n, T d);
};
On souhaite définir, en dehors de la définition de la classe, un constructeur qui crée un objet FractionGeneralisee à partir de deux valeurs de type T (typiquement des nombres). Quelle est la seule définition correcte parmi ces lignes?
template<typename T>
FractionGeneralisee<T>::FractionGeneralisee(T n, T d) : num(n), den(d) {}
Reprenons notre classe FractionGeneralisee, avec le code complet ci-dessous: déclaration de la classe, constructeur inline, et une fonction qui retourne la valeur de la fraction si le nénominateur n'est pas nul.
Que faut-il écrire dans le main() pour afficher 0.666667 ? (Plusieurs réonses possibles)
#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class FractionGeneralisee {
T num;
T den;
public:
FractionGeneralisee(T n, T d) : num(n), den(d) {};
template<typename U> U valeur();
};
template <typename T> template <typename U>
U FractionGeneralisee<T>::valeur() {
if (den != 0) {
return (U) num / (U) den;
} else {
return 0;
}
} int main() {
FractionGeneralisee<int> fg(2, 3);
cout << fg.valeur<double>();
}
int main() {
FractionGeneralisee<double> fg(2, 3);
cout << fg.valeur<double>();
}
On souhaite maintenant afficher nos fractions généralisées comme 2/3 (par exemple), en surchargeant l'opérateur << et en le déclarant comme "friend" dans la classe FractionGeneralisee.
Comment faut-il procéder?
Écrire une pré-déclaration de la classe FractionGeneralisee, puis la définition surchargée de <<, puis la définition de la classe contenant la déclaration d'amitié
Quelle est la forme correcte de la surcharge de l'opérateur de flux << pour afficher des fractions généralisées? Une seule solution est correcte.
Attention, il s'agit de la définition de l'opérateur, et non pas de la déclaration d'amitié, qui, elle, accepte plusieurs variantes.
template<typename T>
ostream& operator << (ostream& os, const FractionGeneralisee<T>& fg) {
return os << fg.num << "/" << fg.den;
}