Est-ce que C++17 peut déduire les paramètres `auto` non-type `template` pattern-match des templates avec des paramètres explicites non-type?

considérez cet exemple (également disponible sur wandbox):

template <template <auto> class>
void test() { }

template <int> 
struct X { };

Essaie d'instancier test<X>()clang++ 4,0(le tronc) résulte en une erreur de compilation:

error: no matching function for call to 'test'
     test<X>();
     ^~~~~~~

note: candidate template ignored: 
      invalid explicitly-specified argument for 1st template parameter
void test() { }

mon hypothèse/intuition initiale était que test peut être utilisée pour correspondre à n'importe template ayant un paramètre non-type.


Toutefois, l'extrait de code suivant avec succès compile:

template <template <auto> class>
void test() { }

//        vvvv
template <auto> 
struct X { };

Est - ce destiné? Ne pouvait pas trouver quelque chose de concluant dans P0127R2.

10
demandé sur TemplateRex 2016-10-02 04:50:56

2 réponses

c'est définitivement prévu. Les paramètres de Template-template ne peuvent correspondre qu'à des templates qui prennent les mêmes types d'arguments. Ceci:

template <template <auto> class>
void test() { }

ne peut être instancié avec un modèle de classe qui peut prendre type de paramètre non-type. Mais ceci:

template <int> 
struct X { };

n'est pas un modèle de classe. X ne peut être instancié avec un int. Simplement, il ne correspond pas à la spécification du modèle paramètre du modèle, d'où l'erreur. Quel si test voulait instancier son modèle de classe avec un type de pointeur? Ou pointer vers la fonction ou pointer vers le membre? Ce serait impossible.

Votre deuxième tentative, avec template <auto> struct X { }; correspondent au paramètre template-template, donc bien formé. Notez également que l'inverse, avoir testtemplate <int> class paramètre et en le passant dans template <auto> struct X { }; est aussi bien formé que l'argument est plus général que le paramètre.


Le la formulation pertinente se trouve dans [temp.arg.modèle]:

modèle-argument correspond à un modèle template-parameterP lors de chacun des paramètres du modèle dans le template-parameter-listemodèle-argument’s correspondant de la classe de modèle ou alias template A les matchs le modèle correspondant paramètre dans le template-parameter-listeP. Deux paramètres de modèle match si ils sont de même nature (type, non-type, modèle), pour les non-type modèle-paramètres, leurs types sont équivalent (14.5.6.1), et pour le modèle modèle-paramètres, chacune de leurs correspondances modèle-paramètres correspond, de manière récursive.


Note: la formulation d'équivalence accepte le auto -auto case et rejette le auto -int cas, mais semble aussi rejeter le int - auto case (d'après ma lecture). Je vais essayer d'obtenir quelques éclaircissements sur elle.

9
répondu Barry 2016-10-02 04:03:35

en plus de la réponse de Barry, qui m'a rendu curieux, voici les quatre combinaisons possibles et les résultats en utilisant Clang 4.0 (SVN),voir aussi sur wandbox:

template <bool> struct obj_bool { };  // object taking a value of boolean type
template <auto> struct obj_auto { };  // object taking a value of deduced type
//       ^^^^^^ Note: this is a template value argument (non-type template argument)

template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
//        ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
//                 ^^^^^^                taking a template value argument

int main() {     
    fn_bool<obj_bool>();    // #1 bool->bool OK (exact match)
    fn_auto<obj_auto>();    // #2 auto->auto OK (exact match)
    fn_bool<obj_auto>();    // #3 bool->auto OK (sub-set)
    //fn_auto<obj_bool>();  // #4 auto->bool Error: no matching function.
}

A partir de cela, les #1 et #2 sont évidemment des Correspondances exactes et fonctionnent comme prévu. #3 appellerait l'implémentation bool sur un template qui peut gérer non seulement bool mais tous les types, tandis que #4 essaierait d'invoquer une définition attendant un objet généralisé (auto) avec un objet prévoir uniquement un sous-ensemble (bool) de possibilités.

basé sur un modèle de La fonction fn_auto promet des instanciations possibles pour les gabarits prenant n'importe quel type de valeur (auto). Ce qui lui donne seulement un sous-ensemble de possibilités (bool) viole cette promesse.

bien qu'elle ne soit pas évidente, la restriction a du sens. Et désolé pour mon libellé de ne pas être en C++ compatible avec le Standard.

2
répondu m-j-w 2016-10-02 10:29:13