IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Appel à la bonne version d'une fonction template


Sujet :

C++

  1. #1
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut Appel à la bonne version d'une fonction template
    Bonjour à toutes et à tous !
    J'ai un petit souci technique, désolé du titre très peu évocateur, j'ai aucune idée du nom du problème que je rencontre !

    Je cherche à comparer les temps d'exécution de différentes stratégies de simulation via des classes de politiques.
    Mais je ne sais pas comment appeler la bonne version template de la fonction à évaluer, parce que je ne lui ai pas encore donné ses arguments ! J'imagine que c'est assez classique comme problème mais je ne sais pas trop où/quoi chercher, et ça fait une petite heure que je me tords le neurone

    Voyez plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
     
    template<typename F, typename... Args>
    double execution_time(F func, Args&&... args){
        auto t1 = std::chrono::high_resolution_clock::now();
        func(std::forward<Args>(args)...);
        return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - t1).count();
    }
     
    //! \remark Merger est une classe de politique donnant la stratégie de simulation
    template<class Merger, typename Generator, typename... Args>
    void repeat_WF(unsigned int n, unsigned int k, Generator& gen, Args&&... args){
      for(unsigned int i = 0; i < n; ++i){
        std::vector<int> v(k);
        auto model = model::make_discrete_time_wright_fisher<Merger>(v.begin(), v.end(), std::forward<Args>(args)... );
        model(gen);
      }
    }
    Le code suivant compile et tourne, mais la dernière ligne commentée ne marche évidemment pas. La version bourrine serait peut-être de préciser tous les arguments template avec l'argument de fonction, mais c'est super moche non ? Il y a moyen de faire autrement ? J'hésite à bricoler une fonction qui instantie une lambda...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    int main(){
     
        using namespace coalescence;
        using BigInt = boost::multiprecision::cpp_int;
        using BigFloat = boost::multiprecision::cpp_dec_float_50;
        using SMM1_type = SimultaneousMultipleMerge<on_the_fly>;
        using SMM2_type = SimultaneousMultipleMerge<in_memoized_distribution<BigInt, BigFloat>>;
        using time_type = int;
        std::mt19937 gen;
     
        unsigned int k = 20;
        unsigned int N = 100;
        unsigned int g = 10;
        time_type t0 = 0;
     
        auto coal_event = std::plus<int>();
        auto init_parent = [](time_type t){return 0;};
     
        // ça c'est juste pour montrer qu'au moins on arrive à simuler selon différentes politiques/stratégies
        repeat_WF<BinaryMerge>(10, k, gen, N, g, t0, coal_event, init_parent);
        repeat_WF<SMM1_type>(10, k, gen, N, g, t0, coal_event, init_parent);
        repeat_WF<SMM2_type>(10, k, gen, N, g, t0, coal_event, init_parent);
     
        //std::cout << execution_time(repeat_WF<BinaryMerge>, 10, k, gen, N, g, t0, coal_event, init_parent) << std::endl; // ne marche pas, snif !
     
      return 0;
    }
    Merci d'avance !
    Bien à vous,
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  2. #2
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Salut,

    En attendant une potentielle meilleure réponse, voici une solution pas générique, mais simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<class Merger, typename Generator, typename... Args>
    double execution_time_repeat_WF(unsigned int n, unsigned int k, Generator& gen, Args&&... args) {
    	return execution_time(repeat_WF<Merger, Generator, Args...>, n, k, gen, std::forward<Args>(args)...);
    }
    Exemple d'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    execution_time_repeat_WF<BinaryMerge>(10, k, gen, N, g, t0, coal_event, init_parent)

  3. #3
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Un foncteur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class Merger>
    struct repeat_WF_fn
    {
      template<typename Generator, typename... Args>
      void operator()(unsigned int n, unsigned int k, Generator& gen, Args&&... args) const 
      { /*...*/  }
    };
     
    // http://en.cppreference.com/w/cpp/language/variable_template
    template<class Merger>
    constexpr auto repeat_WF = repeat_WF_fn<Merger>{};

  4. #4
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Solution alternative : une macro :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define EXECUTION_TIME(expr) \
    	([&] {\
    		auto EXECUTION_TIME_t1 = std::chrono::high_resolution_clock::now();\
    		static_cast<void>(expr);\
    		return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - EXECUTION_TIME_t1).count();\
    	}())
    Exemple d'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EXECUTION_TIME(repeat_WF<BinaryMerge>(10, k, gen, N, g, t0, coal_event, init_parent))
    Personnellement, je préfère la solution de jo_link_noir. Ma solution avec une macro, ce serait plutôt si le code de repeat_WF ne pouvait pas être changé.

    Edit 2017-04-27-14h18 : t1 renommé en EXECUTION_TIME_t1 pour éviter de potentielles collisions de nom.

  5. #5
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Merci à tous pour vos réponses !

    Citation Envoyé par jo_link_noir Voir le message
    Un foncteur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class Merger>
    struct repeat_WF_fn
    {
      template<typename Generator, typename... Args>
      void operator()(unsigned int n, unsigned int k, Generator& gen, Args&&... args) const 
      { /*...*/  }
    };
     
    // http://en.cppreference.com/w/cpp/language/variable_template
    template<class Merger>
    constexpr auto repeat_WF = repeat_WF_fn<Merger>{};
    Ok, donc on instantie le foncteur avec la police adaptée, et le reste de l'instantiation est repoussé à l'opérateur parenthèse. Logique. Sauf que je comprends mal l'utilisation de la variable template... Je crois avoir compris l'exemple classique des variables template avec PI, mais dans notre contexte je vois moins bien.
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  6. #6
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    La variable template permet d'alléger un peu l’écriture. Pour utiliser repeat_WF_fn, il faut faire repeat_WF_fn<P>{}(params...). La paire d'accolade sert à instancier le foncteur et les parenthèses appel la fonction membre.
    Avec la variable template repeat_WF<P>, cela crée une instance de repeat_WF_fn (cf: repeat_WF_fn<P>{}. Il n'y a donc plus besoin des accolades.

    repeat_WF<P> = repeat_WF_fn<P>{}.
    repeat_WF<P>(params...) = repeat_WF_fn<P>{}(params...).

    Cela donne la fausse impression d'utiliser une fonction ^^.

  7. #7
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Ooooooh mais c'est super joli !
    Merci encore à vous deux !
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 07/06/2016, 22h25
  2. Appel d'une fonction template de façon explicite
    Par vanitom dans le forum Langage
    Réponses: 11
    Dernier message: 10/12/2008, 14h34
  3. [langage] appel d'un tableau dans une fonction
    Par donny dans le forum Langage
    Réponses: 11
    Dernier message: 13/11/2006, 16h17
  4. Pointeur sur une fonction template
    Par Progs dans le forum Langage
    Réponses: 2
    Dernier message: 15/02/2006, 20h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo