2
votes

Signature de fonction fractionnée de lambda dans la correspondance de modèle de spécialisation en c ++

J'ai le code suivant:

#include <iostream>                                                                                                                         
#include <string>                                                                                                                           
#include <array>                                                                                                                            
#include <map>                                                                                                                              
#include <functional>                                                                                                                       

template<typename T> struct tag {};                                                                                                         

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    split(LambdaType &&f) {                                                                                                                 
        std::cout << "[]()" << std::endl;                                                                                                   
    }                                                                                                                                       
};                                                                                                                                          

template <typename RetType, typename... ArgTypes>                                                                                           
struct split<std::function<RetType(ArgTypes...)>>  {                                                                                        
    split(std::function<RetType(ArgTypes...)> &&f) {                                                                                        
        std::cout << "std::function" << std::endl;                                                                                          
    };                                                                                                                                      
};                                                                                                                                          

template <typename RetType, typename... ArgTypes>                                                                                           
struct split<RetType(*)(ArgTypes...)> {                                                                                                     
    split(RetType(*f)(ArgTypes...)) {                                                                                                       
        std::cout << "func-ptr" << std::endl;                                                                                               
    };                                                                                                                                      
};                                                                                                                                          

void f1(int) {};                                                                                                                            

int                                                                                                                                         
main(int argc, char **argv) {                                                                                                               

    new split<std::decay<decltype(f1)>::type>(f1);                                                                                          
    new split<std::function<void(int)>>(std::function<void(int)>([](int) {}));                                                              

    /* how can I extract the argument type template pack from lambda ? */                                                                   
    new split([](int){});                                                                                                                   
    return 0;                                                                                                                               
}   

Il y a 2 spécialisations pour split , une pour std :: function et un pour RetType (*) (ArgTypes ...) . Pour les deux spécialisations, j'obtiens l'argument de modèle RetType et ArgTypes ... et le pack par correspondance de modèle. Cependant, je me demande s'il y a un moyen de faire la même chose avec un lambda comme argument?

Comment puis-je extraire RetType et ArgTypes. .. d'un lambda dans une spécialisation pour la ligne new split ([] (int) {}) ?


7 commentaires

Vous pouvez obtenir le type de retour en utilisant ceci . Je ne sais pas si vous pouvez obtenir le (s) type (s) d'argument


Vous pouvez essayer SFINAE sur is_convertible en RetType (*) (ArgTypes ...) . Cela marcherait-il pour toi? De cette façon, vous gérerez également des lambdas sans captivité.


@Barry Duplicate consiste à déduire le type de retour d'une fonction, tandis que cette question consiste à déduire à la fois le type de retour et les types d'argument d'un type lambda (fermeture).


@Barry (je ne voulais pas rouvrir seul sans discussion, je voulais voter ... mais j'ai oublié que dupe-hammer vient avec reopen-hammer.)


@Holt Heh, je sais bien - les problèmes du marteau ... Mais de toute façon, je pense que cette réponse répond à cette question. Et pour ce que ça vaut - la partie de cette réponse qui ne répond pas à cette question n'est pas non plus incluse dans votre réponse, non?


@Barry Seule la première réponse de la dupe s'applique, et même dans ce cas, elle est principalement ciblée sur le type de retour. Cependant, je conviens que ma réponse n'est pas si meilleure, mais celle de SergyA peut ajouter quelque chose. Si les OP trouvent la dupe suffisante, alors trompons-la.


@KonradEisele ceci répond à votre question? Sinon, pourriez-vous clarifier comment vous souhaitez utiliser les types de retour / arguments afin que nous puissions développer les réponses ici.


3 Réponses :


2
votes

Vous pouvez utiliser la déduction des arguments de classe de modèle avec std::function:

template<class F>
function(F) -> function</*see below*/>;

Une fois que vous avez la std :: function correspondante à votre lambda, vous pouvez récupérer les types de retour et d'argument en utilisant la spécialisation de modèle.

Cela fonctionne car std :: function a un guide de déduction :

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    using StdFunctionType = decltype(std::function{std::declval<LambdaType>()});                                                                                                                                  
};     

Si decltype (& F :: operator ()) est de la forme R (G :: *) (A ...) (éventuellement cv -qualifié, éventuellement noexcept , éventuellement lvalue référence qualifiée) pour un type de classe G , alors le type déduit est std :: function . Cette surcharge ne participe à la résolution de la surcharge que si & F :: operator () est bien formé lorsqu'il est traité comme un opérande non évalué.


0 commentaires

2
votes

Vous pouvez passer par une sorte de supercherie, par exemple:

#include <type_traits>

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    split(LambdaType &&f) { deduce(&LambdaType::operator()); }
    template<class RET, class CLOSURE, class... ARGS>
    void deduce(RET(CLOSURE::*)(ARGS...) const) {
       // You have your return and args here
    }
};                                                                                                                                          


template <typename RetType, typename... ArgTypes>                                                                                           
struct split<RetType(*)(ArgTypes...)> {                                                                                                     
    split(RetType(*f)(ArgTypes...));                                                                                                                                      
};                                                                                                                                  

void f1(int) {};                                                                                                                            

int                                                                                                                                         
main(int argc, char **argv) {                                                                                                               

    split<std::decay_t<decltype(f1)>>{f1};                                                                                          

    /* how can I extract the argument type template pack from lambda ? */                                                                   
    split([](int){});                                                                                                                   
    return 0;                                                                                                                               
}   


3 commentaires

Petite (tellement petite) mise en garde, cela ne fonctionne pas (directement) avec mutable lambda en raison de la const -qualification de l'opérateur d'appel dans deduce () < / code>.


Question: Existe-t-il un prédicat de trait de type pour tester si un type est un lambda?


J'ai ajouté une méthode que j'ai trouvée comme réponse ci-dessous. J'utilise le sous-classement du cas de spécialisation pour l'opérateur lambdas () ... C'est un peu comme votre méthode mais en utilisant des sous-classes.



0
votes

J'ai trouvé une méthode qui utilise la sous-classification de la spécialisation (vue ici ):

/* g++ -std=c++17 */
#include <iostream>
#include <string>
#include <array>
#include <map>
#include <functional>

template<typename T> struct tag {};
struct mybase {};

/* subclass specialization on type of operator() of lambda: */
template<class Ld>
struct split : split<decltype(&Ld::operator())>
{
    split(Ld &&f) : split<decltype(&Ld::operator())>(std::forward<Ld>(f)) {};
};

template <typename RetType, typename... ArgTypes>
struct split<std::function<RetType(ArgTypes...)>>  {
    split(std::function<RetType(ArgTypes...)> &&f) {
        std::cout << "std::function" << std::endl;
    };
};

template <typename RetType, typename... ArgTypes>
struct split<RetType(*)(ArgTypes...)> {
    split(RetType(*f)(ArgTypes...)) {
        std::cout << "func-ptr" << std::endl;
    };
};

template <typename RetType, class Cls, typename... ArgTypes>
struct split<RetType(Cls::*)(ArgTypes...) const >  {
    split(const Cls &&f) {
        std::cout << "[]() const" << std::endl;
    };
};

template <typename RetType, class Cls, typename... ArgTypes>
struct split<RetType(Cls::*)(ArgTypes...) >  {
    split(Cls &&f) {
        std::cout << "[]()" << std::endl;
    };
};


void f1(int) {};

int
main(int argc, char **argv) {

    new split<std::decay<decltype(f1)>::type>(f1);
    new split<std::function<void(int)>>(std::function<void(int)>([](int) {}));

    /* no g++-17: */
    //auto l = [](int){};
    //new split<decltype(l)>(std::forward<decltype(l)>(l));

    /* g++-17: */
    new split([](int){});

    return 0;
}


0 commentaires