Salut,
Envoyé par
goran kajfes
Mince, c'était dans la section Details. Mais ils ne parlent pas de l'ordre imposé des templates.
En fait, si tu ne définis pas de paramètre modèle par défaut, il n'y a pas vraiment d'ordre imposé...
Par contre, si tu le fait, tu es soumis aux mêmes restrictions que lorsque tu donne une valeur par défaut un argument de fonction, à savoir qu'un argument peut avoir une valeur par défaut si c'est le dernier de la liste d'arguements (juste avant la fermeture de la parenthèse) ou s'il est suivi d'un argument par défaut, et que tu ne peux pas utiliser la valeur par défaut pour un argument si tu dois préciser la valeur d'un des arguments qui suivent.
Comme il est à l'extrême limite possible de déterminer le type d'arguments réels que prendrait une fonction dont on a identifié le type de retour, mais qu'il est beaucoup plus difficile, sur base du type des arguments que prend une fonction, de déterminer le type de la valeur de retour, ce n'est donc que la pure logique qui fait que le type de la valeur de retour prend "naturellement" place en première position
Pour te faire comprendre ce que j'ai écrit (qui n'est effectivement peut être pas très clair :aei, considère cette fonction template:
1 2 3 4 5
| template <class T, class U, class V>
T foo(U u, V v)
{
/*...*/
} |
Il s'agit d'une fonction qui manipule trois type distincts, nommés T, U et V, servant respectivement comme valeur de retrour, premier et second argument de la fonction.
Chaque fois que tu voudrais l'utiliser, tu devrais indiquer explicitement les types respectifs pour T, U et V, sous une forme proche de
double d=foo<double, int*, long*>(mondouble, ptrint, ptrlong);
mais cela pourrait tout aussi bien être (si les deux arguments sont sensés être des collections d'objets)
MonObjet = foo<MonObjet, std::vector<Objet2>, std::list<Objet3> >(tab, lalist);
Or, c'est là que tu te rend compte que le deuxième argument à fournir pourrait très bien être le même que le premier... Et que ce sera, selon toute vraisemblance, le plus souvent le cas.
Tu serais alors tenté de donner une valeur par défaut au deuxième type template, sous la forme de
1 2 3 4
| template <class T, class U, class V= U>
T foo(U u, V v)
{
} |
les deux appels que je t'ai présentés plus hauts restent valables, mais cela te permet, si la fonction doit renvoyer un MonObjet et prendre deux std::vector<Objet2> de simplifier l'appel en
MonObjet res=foo(MonObjet, std::vector<Objet2> >(truc, tab1, tab2);
Et c'est enfin là que tu te rend compte, que, le plus souvent, ta fonction renverra un objet de type T parce qu'elle a travaillé avec... des std::vector<T> pour les deux arguments (bien qu'il soit possible qu'il en soit autrement)...
Pour que les différents appels présentés plus haut reste corrects, il faut toujours garder la possibilité de fournir trois types, mais, à bien y réfléchir, seul le premier présente un intérêt réel...
Tu finirais donc en donnant une valeur par défaut au deuxième type template, sous la forme de
1 2 3 4 5
| template <typename T, class U=std::vector<T>, class V=U>
T foo(U u, V v)
{
/*...*/
} |
qui pourra être appelée sous la forme "simple" de
MonObjet obj=foo<MonObjet>(truc, tab1, tab2);
qui continuera malgré tout à travailler avec les appels précédents
J'ai bien sur "déroulé" l'ensemble du raisonnement, pour bien te le faire comprendre, mais tu pourrais très bien arriver à la dernière solution "en une seule passe"
Partager