15 votes

Le pack de paramètres doit se trouver à la fin de la liste des paramètres... Quand et pourquoi ?

Je ne comprends pas la raison pour laquelle un paquet de paramètres doit se trouver à la fin de la liste de paramètres si cette dernière est liée à une classe, alors que la contrainte est relâchée si la liste de paramètres fait partie de la déclaration d'une méthode membre.

En d'autres termes, celui-ci compile :

class C {
    template<typename T, typename... Args, typename S>
    void fn() { }
};

La suivante ne l'est pas :

template<typename T, typename... Args, typename S>
class C { };

Pourquoi le premier cas est-il considéré comme juste et le second non ?
Je veux dire, si c'est une syntaxe légale, ne devrait-elle pas l'être dans les deux cas ?

Pour être clair, le vrai problème est que je définissais une classe similaire à la suivante :

template<typename T, typename... Args, typename Allocator>
class C { };

Avoir le type allocateur comme dernier type serait apprécié, mais je peux contourner cela d'une manière ou d'une autre (de toute façon, si vous avez une suggestion, elle est appréciée, peut-être que les vôtres sont beaucoup plus élégantes que les miennes !)
Cela dit, j'ai eu l'erreur :

Le paquet de paramètres 'Args' doit se trouver à la fin de la liste des paramètres du modèle.

J'étais donc curieux de bien comprendre pourquoi il est accepté dans certains cas, mais pas dans d'autres.

Ici est une question similaire, mais elle explique simplement comment résoudre le problème et c'était assez clair pour moi.

14voto

user657267 Points 5796

C'est valable pour les modèles de fonction, mais seulement lorsque la déduction des arguments peut aider le compilateur à résoudre les paramètres du modèle. En l'état actuel, votre exemple de modèle de fonction est pratiquement inutile car

template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }

test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
 int main() { fn<int, int, int>(); }
                                ^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
 template<typename T, typename... Args, typename S> void fn() { }
                                                         ^
test.cpp:1:57: note:   template argument deduction/substitution failed:
test.cpp:2:32: note:   couldn't deduce template parameter 'S'
 int main() { fn<int, int, int>(); }

le compilateur n'a aucun moyen de déterminer quels paramètres de gabarit appartiennent au paquet de paramètres, et quels sont ceux qui appartiennent à l'ensemble des paramètres. S . En fait, comme le souligne @T.C., il devrait s'agir d'une erreur de syntaxe car un modèle de fonction défini de cette manière ne peut jamais être instancié.

Un modèle de fonction plus utile serait quelque chose comme

template<typename T, typename... Args, typename S> void fn(S s) { }

car maintenant le compilateur est capable de faire correspondre sans ambiguïté le paramètre de fonction s avec le type de modèle S avec l'effet secondaire suivant S sera toujours être déduit - tous les paramètres explicites du modèle après le premier appartiendront à Args .

Rien de tout cela ne fonctionne pour les modèles de classes (primaires), les paramètres ne sont pas déduits et c'est expressément interdit :

Du projet n4567

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf

[temp.param] / 11

[...] Si un Paramètre du modèle d'un modèle de classe primaire ou d'un alias est un paquet de paramètres de modèle, il doit être le dernier paquet de paramètres de modèle. Paramètres du modèle .[...]

(s'ils étaient déduits, ce serait ambigu comme dans l'exemple du modèle de fonction).

8voto

T.C. Points 22510

Le premier n'est pas correct. Le compilateur est juste bogué et n'a pas réussi à le diagnostiquer. [temp.param]/11 :

Un paquet de paramètres d'un modèle de fonction ne doit pas être suivi par un autre paramètre de modèle, sauf si ce paramètre de modèle peut être déduit du liste de types de paramètres du modèle de fonction ou a un argument par défaut (14.8.2).


Si le type de fonction T(Args...) est significative pour l'utilisateur final, une façon de résoudre ce problème serait d'utiliser une spécialisation partielle à la place :

template<class F, class Alloc> class C; //undefined
template<class T, class... Args, class Alloc>
class C<T(Args...), Alloc> {
    // implementation
};

En fonction des besoins réels, l'effacement de type de l'allocateur peut également être envisagé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X