web-dev-qa-db-fra.com

Avons-nous encore besoin d'écrire les crochets vides lors de l'utilisation d'objets fonction std transparents?

Avec la déduction d'argument de modèle de classe, nous pouvons écrire:

std::less Fn;

Cependant, G ++ 8.2 rejette ce code:

#include <algorithm>
#include <vector>
#include <functional>

int main()
{
std::vector v= { 1, 3, 2, 7, 5, 4 };

std::sort(v.begin(),v.end(),std::greater());
}

émettant l'erreur suivante:

error: cannot deduce template arguments for 'greater' from ()

Clang ++ 7.0 et MSVC 15.8.0 le compilent sans avertissements. Quel compilateur a raison?

34
metalfox

GCC a tort. Il y a déjà un rapport de bogue .

[dcl.type.simple]/2 dit:

A type-specifier de la forme typename opt  spécificateur de nom imbriqué opt  template-name est un espace réservé pour un type de classe déduit ([dcl.type.class.deduct]).

Et [dcl.type.class.deduct]/2 dit:

Un espace réservé pour un type de classe déduit peut également être utilisé dans le type-specifier-seq dans le new-type-id ou type- id of new-expression, as the simple-type-specifier dans un type explicite conversion (notation fonctionnelle) ([expr.type.conv]), ou comme spécificateur de type dans la déclaration-paramètre d'un paramètre-modèle. Un espace réservé pour un type de classe déduit ne doit apparaître dans aucun autre contexte.

Une telle utilisation est autorisée.


[temp.arg]/4 décrit l'erreur de syntaxe qui template-id est requis mais il n'y a pas de <>. Cependant ici std::greater n'est pas résolu comme un template-id afin que le paragraphe ne s'applique pas.

28
xskxzr

Clang et MSVC sont corrects. Cela devrait être bien formé en raison de l'effet de combinaison de guides de déduction générés implicitement (depuis C++ 17) et de l'argument de modèle par défaut.

(c'est moi qui souligne)

Lorsqu'une conversion ou une déclaration de style fonction d'une variable utilise le nom d'un modèle de classe primaire C sans liste d'arguments comme spécificateur de type, la déduction se déroule comme suit:

  • Si C est défini, pour chaque constructeur (ou modèle de constructeur) Ci déclaré dans le modèle principal nommé (s'il est défini), un modèle de fonction fictive Fi, est construit, tel que
    • les paramètres de modèle de Fi sont les paramètres de modèle de C suivis (si Ci est un modèle de constructeur) par les paramètres de modèle de Ci ( les arguments de modèle par défaut sont également inclus )
    • les paramètres de fonction de Fi sont les paramètres du constructeur
    • le type de retour de Fi est C suivi des paramètres de modèle du modèle de classe inclus dans <>
  • Si C n'est pas défini ou ne déclare aucun constructeur, un modèle de fonction fictive supplémentaire est ajouté, dérivé comme ci-dessus d'un constructeur hypothétique C ()
  • Dans tous les cas, un modèle de fonction fictive supplémentaire dérivé comme ci-dessus d'un constructeur hypothétique C(C) est ajouté, appelé candidat à déduction de copie.

La déduction d'argument de modèle et la résolution de surcharge sont ensuite effectuées pour l'initialisation d'un objet fictif de type classe hypothétique, dont les signatures de constructeur correspondent aux guides (sauf pour le type de retour) dans le but de former un ensemble de surcharge, et l'initialiseur est fourni par le contexte dans quelle déduction d'argument de modèle de classe a été effectuée, sauf que la première phase d'initialisation de liste (en considérant les constructeurs de liste d'initialisation) est omise si la liste d'initialisation consiste en une seule expression de type (éventuellement qualifié cv) U, où U est une spécialisation de C ou d'une classe dérivée d'une spécialisation de C.

Ces constructeurs fictifs sont des membres publics du type de classe hypothétique. Ils sont explicites si le guide a été formé à partir d'un constructeur explicite. Si la résolution de surcharge échoue, le programme est mal formé. Sinon, le type de retour de la spécialisation de modèle F sélectionnée devient la spécialisation de modèle de classe déduite.

Étant donné std::greater(), le guide de déduction généré implicitement est appliqué et la fonction fictive supplémentaire est enfin sélectionnée. En raison de la résolution de surcharge, l'argument par défaut void est appliqué, puis le type déduit sera void. Cela signifie que std::greater() doit être identique à l'écriture de std::greater<void>() ou std::greater<>().


BTW: Gcc ne compile pas avec std::greater(), mais std::greater{} ou std::greater g; vont bien, c'est peut-être le bogue de gcc.

14
songyuanyao