0
votes

La fonction de fonctionnement de la fonction membre Substitution de la substitution échoue

J'ai le code suivant:

template<class T, typename F, typename ... ARGS>
std::function<void()> * invoke(T *t, F const &fn, ARGS... args) {
    std::function<void()> *f = new std::function<void()>([=]() { (t->*fn)( args... ); });

    return f;
}


1 commentaires

Pourquoi avez-vous besoin invoke () du tout? Surtout que vous exécutez le risque de myA sortir de la portée avant fn est utilisé? Pourquoi pas seulement avoir l'appelant créer un Lambda directement, puis le transmettre au besoin? une mya; B myb (5, 6, 7); auto fn = [=] () {mya.foo (myB); }; // utilise fn si nécessaire ...


4 Réponses :


1
votes

Votre invoquer la fonction est déjà appelé std :: lid et si vous voulez vous assurer que les paramètres de FOO ne sont pas copiés, alors combinez lidez avec CREF : xxx


0 commentaires

1
votes

Tout d'abord, vous devriez vraiment utiliser std :: Transférer code> lors de la gestion des paquets de paramètres. En ce moment, vous prenez tous les paramètres comme des valeurs.

Deuxièmement, la compilation échoue parce que le type de déduction est conflits entre Void (T :: * fn) (args ...) code> et args .. . args code>. Le compilateur sera confus sur le point de prendre des types de args code> ou de votre fonction. Par exemple, A :: FOO code> prend un const B & code> mais vous lui donnez un type de valeur B code> également, ce qui conduit à un conflit. Donc, vous avez réellement besoin de deux paquets de paramètres distincts pour éviter cela. P> xxx pré>

Vous pouvez également utiliser std :: lid code> qui fait exactement ce que vous êtes Essayer d'accomplir: P>

std::function<void()> fn = std::bind(&A::foo, &myA, myB);


5 commentaires

Je crée la fonction sur un tas car ce pointeur sera effectivement ajouté à une file d'attente dans Freertos qui copie ses données par valeur à l'aide de MEMCY ().


Dans ce cas, vous pourriez toujours simplement déplacer ce résultat sur le tas comme nouveau STD :: Fonction {std :: déplacer (fn)} . Ce serait plus élégant que de forcer l'allocation de tas dans invoquer .


Pour une raison quelconque, si je modifie mon code comme suggéré ([&, T] () {(T -> * fn) (STD :: Transférer (args) ...);};) il provoque le processeur à la faute à ce moment-là. Cependant, si je le laissais comme une Lambda en utilisant une copie-by-value et arguments AS && pour un transfert parfait, tout fonctionne, cependant, pour une raison quelconque, deux copies de la valeur en actions sont faites au lieu d'une.


J'ai couru ce code exact et ça n'a pas échoué, alors je ne suis pas sûr de ce qui pourrait en être la cause. Il est difficile de dire juste de votre description. Aucune copie de mon doit être faite du tout, car la Lambda stocke une référence au lieu d'une copie.


En fait, je veux une copie (et une seule) des arguments à effectuer avant que la fonction soit ajoutée à la file d'attente, car il n'y a aucune garantie qui et lorsque le thread de réception accédera aux données. Par exemple, si j'invoque une fonction à l'aide d'une variable locale / temporaire (I.E. sur la pile de l'appelant), une copie doit être prise afin que les données soient disponibles pour le fil de réception.



0
votes

Arguments de Invoke code> et les arguments de votre fonction de membre sont pas em> les mêmes. On obtient une référence de const, l'autre ne le fait pas. Cela doit être reflété dans les types.

template<class T, 
         typename ... ARGS, 
         typename ... ARGS2> // <---- !!
std::function<void()> * invoke(T *t, 
                               void(T::* fn)(ARGS2...) // <---- !! 
                               ARGS&&... args) { // you do want perfect forwarding


0 commentaires

0
votes

J'ai trouvé une solution qui fonctionne pour moi basée sur les réponses et les commentaires de chacun.

Dans ma demande, je dois m'assurer que l'un, et une seule copie des arguments à la fonction en cours d'invocation est apportée car La fonction sera exécutée dans un fil différent à un moment différent et les données d'origine peuvent ne pas être disponibles (par exemple, une variable temporaire sur la pile). J'avais modifié mon code, comme suggéré, d'utiliser un transfert parfait dans mes fonctions de matrice. Cela a contribué à réduire considérablement des copies inutiles, cependant, j'avais toujours une copie supplémentaire dans la Lambda de ma fonction d'invoque. Il s'avère, j'avais écrit le constructeur de déplacement de mon type de données de manière incorrecte, lorsque la Lambda a créé une copie temporaire des données, il devait être copié deux fois.

Voici des extraits de mon code de travail ( avec mon exemple de type de données B): xxx

J'ai également montré ici une autre fonction, connectez-vous, qui enregistre une lambda à appeler ultérieurement, appelle la fonction d'invocation.

avec tout cela, seule une seule copie du type de données est faite aussi longtemps que a) L'argument de la fonction membre (FN) est d'un type de référence b) le type de données a un constructeur de déplacement de travail


0 commentaires