2016-09-20 3 views
4

Peut-être que c'est la grippe, ou je suis tout simplement stupide, mais je ne peux pas comprendre une partie de this code cadre Corbeau. Mon analyseur C++ interne échoue.Incapable de comprendre ce paramètre de modèle

template <typename MW> 
struct check_before_handle_arity_3_const 
{ 
template <typename T, 
    //this line 
    void (T::*)(int, typename MW::context&) const = &T::before_handle 
    > 
    struct get 
    { }; 
}; 

Je sais que c'est un paramètre de modèle dans la déclaration de modèle. Cela ressemble peut-être à un paramètre de type lambda ou pointeur de fonction ... mais, je ne suis pas sûr. Quelqu'un peut-il expliquer cette ligne?

Mise à jour: Exploring profondeurs de nouvelles connaissances obtenues - après la réponse a été donnée - m'a conduit à cet extrait d'un grand book:

Un modèle peut accepter un pointeur vers une fonction en tant que non typiques modèle paramètre. (Le plus souvent dans ce livre, les paramètres de type non-type sont valeurs intégrales.) [...] Utiliser un pointeur sur une fonction comme argument de type non-type signifie que nous n'avons plus besoin de le stocker dans la carte. Cet aspect essentiel nécessite une compréhension approfondie. La raison pour laquelle nous n'avons pas besoin de stocker le pointeur sur une fonction est que le compilateur a des connaissances statiques à ce sujet. Ainsi, le compilateur peut coder en dur l'adresse de la fonction dans le code du trampoline.

Donc, maintenant je connais une des raisons d'utiliser cette technique.

+1

C'est un pointeur de fonction membre de 'T'. Vous avez oublié de poser une question BTW. –

+2

Mon analyseur de grammaire anglaise ne parvient pas à voir un point d'interrogation. Quelle est votre question? Que ce soit C++? Que ça te tue? –

+0

cette mise à jour est-elle qualifiée de question? – strangeqargo

Répondre

9

void (T::*)(int, typename MW::context&) const est un non-type template parameter. Il s'agit d'un pointeur sur une fonction membre de T.

Avec l'utilisation de = &T::before_handle, sa valeur par défaut est &T::before_handle.

2

La raison pour laquelle j'ai utilisé cette technique consiste à soutenir 2 types de format de gestionnaire: https://github.com/ipkn/crow/blob/master/include/middleware.h#L17

check_before_handle_arity_3_const est utilisé ici:

template <typename T> 
    struct is_before_handle_arity_3_impl 
    { 
     template <typename C> 
     static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*); 

     template <typename C> 
     static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*); 

     template <typename C> 
     static std::false_type f(...); 

    public: 
     static const bool value = decltype(f<T>(nullptr))::value; 
    }; 

Avec SFINAE, is_before_handle_arity_3_impl<T>::value est déterminé si l'on peut appeler le gestionnaire avec 3 arguments ou non. En utilisant std::enable_if, Crow peut appeler le gestionnaire approprié: https://github.com/ipkn/crow/blob/master/include/http_connection.h#L110