std::tr1::function et std::tr1::bind
J'ai un problème à l'aide d'un très compliqué C de la fonction dans une classe C++ (réécriture de la fonction C est pas une option). Fonction C:
typedef void (*integrand) (unsigned ndim, const double* x, void* fdata,
unsigned fdim, double* fval);
//This one:
int adapt_integrate(unsigned fdim, integrand f, void* fdata,
unsigned dim, const double* xmin, const double* xmax,
unsigned maxEval, double reqAbsError, double reqRelError,
double* val, double* err);
J'ai besoin d'une fonction void de type integrand
moi-même, et adapt_integrate de calculer le n-dimensionnelle partie intégrante. Le code de la calcTripleIntegral
(ci-dessous) fonctionne comme une fonction autonome si func
est une fonction autonome).
Je veux passer une (non-statique!) fonction membre de classe que la fonction à intégrer, comme cela peut être facilement surchargé etc...
class myIntegrator
{
public:
double calcTripleIntegral( double x, double Q2, std::tr1::function<integrand> &func ) const
{
//...declare val, err, xMin, xMax and input(x,Q2) ...//
adapt_integrate( 1, func, input,
3, xMin, xMax,
0, 0, 1e-4,
&val, &err);
return val;
}
double integrandF2( unsigned ndim, const double *x, void *, //no matter what's inside
unsigned fdim, double *fval) const; //this qualifies as an integrand if it were not a class member
double getValue( double x, double Q2 ) const
{
std::tr1::function<integrand> func(std::tr1::bind(&myIntegrator::integrandF2, *this);
return calcTripleIntegral(x,Q2,func);
}
}
Sur GCC 4.4.5 (version préliminaire), cela me donne:
erreur: la variable 'std::tr1::function func' a l'initialiseur mais incomplète type
MODIFIER:Quelle est l'erreur dans mon code? Maintenant, j'ai essayé de compiler avec GCC 4.4, 4.5 et 4.6, le tout résultant dans la même erreur. Soit aucun travail n'a été effectué sur ce, ou j'ai fait quelque chose de mal /MODIFIER
Grâce très beaucoup! Si je ne suis pas assez clair, je serai heureux d'élaborer.
PS: Pourrais-je contourner ce sans tr1 trucs à l'aide d'un pointeur de fonction à une fonction définie quelque part dans myIntegrator.cpp?
Dernière mise à JOUR: ok, j'ai eu tort de penser TR1 fourni un/deux-solution en ligne pour cela. La poisse. Je suis à la "conversion" de mes classes d'espaces de noms et copypasting les déclarations de fonction. J'ai seulement besoin d'une classe de base et une sous-classe qui ré-implémenté l'interface. C pointeur de fonction + C++ class = mauvaise nouvelle pour moi.
Merci de toute façon pour toutes les réponses, vous avez de me montrer quelques coins sombres de C++ 😉
Quelles sont les
fdata
et input
paramètres? Pourquoi ne pas le void*
paramètre dans la fonction à intégrer tapez un nom?Caspin, vous n'avez pas besoin de nommer les paramètres d'une fonction dans une déclaration de type. Vous n'avez même pas besoin de les nommer dans la définition même de la fonction si vous n'avez pas besoin de les utiliser dans la fonction. Les gens l'habitude d'écrire ce si leur fonction doit correspondre à une certaine signature pour une utilisation avec un autre code, mais certains paramètres ne seront jamais utilisés dans leur mise en œuvre.
Caspin sait que. Le problème est que nous ne savons pas si
void* fdata
est passé par - si le void*
paramètre pour integrand
a été bien nommé, nous n'aurions pas à deviner/ask.Ah! Je suis bête! J'ai confondu une question de premier plan pour une véritable ignorance. Désolé Caspin!
OriginalL'auteur rubenvb | 2010-07-15
Vous devez vous connecter pour publier un commentaire.
Si vous essayez juste de passer d'une fonction membre dans un style c rappel, vous pouvez le faire avec l'aide d'
std::t1::bind
oustd::tr1::function
.Non, ce qui est parfaitement sûre, portable, et un bon style C++. Je suis le seul à l'aide de la fonction statique pour obtenir l'accès à
myIntegrator
's internes. Si j'ai souhaitéfancy_integrand
pourrait être autonome de la fonction, et tousmyIntegrator
's les membres pourraient être rendus publics. J'aime la méthode statique approche car il est plus encapsulé.Bien que le titre ne peut pas se prêter à une réponse sans lier et/ou de la fonction, il n'résoudre le problème à la main. Merci pour coller avec elle 🙂
OriginalL'auteur deft_code
Vous avez trois problèmes... d'abord, vous voulez un
std::tr1::function<R (Args..)>
, mais le vôtre se résume àstd::tr1::function<R (*)(Args...)>
- si vous avez besoin de deux typedefs:... de sorte que la première permet une compilable
function<integrand>
.adapt_integrate
doit être fixé en conséquence:Suivant votre
bind
syntaxe est éteint, il doit être:Le problème reste que
tr1::function<T>
n'est pas convertible à un pointeur de fonction, alors vous pourriez avoir à passer par un wrapper de la fonction, à l'aide de lavoid* fdata
argument pour passer le contexte. E. g. quelque chose comme:C'est bien sûr en supposant que la
void*
paramètre est transmis à la fonction, sinon il allait devenir laid.D'autre part, si
void* fdata
permet de passer contexte, tout ce quitr1::function
truc est inutile et vous pouvez tout simplement aller directement au travers d'un trampoline la fonction juste à passerthis
à travers le contexte de l'argument:OriginalL'auteur Georg Fritzsche
Depuis
std::tr1::bind
et c-style des pointeurs de fonction ne s'entendent pas, essayez plutôt ceci. Il va travailler, sauf quemyIntegrator::getValue
n'est pas plus "thread-safe". SicalcTripleIntegral
ont été retirés de l'interface, ce serait encore plus simple et n'aurait pas besoin d'utiliserstd::tr1::bind
oustd::tr1::function
.void*
paramètre n'est pas passé à travers 🙂Comment enlever une fonction de commodité comme calcTripleIntegral (qui ne définit/déclare le val, err, d'entrée et de xMin et xMax paramètres) faire std::tr1::bind et de la fonction superflue? Je peux le supprimer, mais ne sais pas comment ça simplifie les choses. Je n'ai jamais utilisé cette tr1 fonctionnalité et n'ai pas trouvé une bonne (pas-boost) explication de celui-ci encore 🙁
Si j'essaie ceci, j'obtiens une erreur à propos de m_integrand avoir un type incomplète 🙁
Comme moi et d'autres ont souligné,
function
ne prend pas une fonction pointeur typefunction<void (*)(int)>
- mais un type de fonction -function<void (int)>
. À l'aide de la première vous donne exactement cette erreur.retrait
caldTripleIntegral
à partir de l'interface, supprime égalementstd::tr1::bind
etstd::tr1::function
à partir de l'interface.getValue
ne dit rien sur la façon dont il est mis en œuvre, deux lits doubles dans une chambre double. En interne, je peux (indirectement) de passer d'une fonction membre deupdapt_integrate
sans l'aide destd::tr1::bind
.OriginalL'auteur deft_code
je veux passer une (non-statique!) fonction membre de classe que la fonction à intégrer...
Vous ne pouvez pas. Si vous recherchez DONC, pour l'utilisation des fonctions membres comme des callbacks vous serez lié pour trouver des informations utiles, y compris le fait que ce que vous essayez de le faire, l'approche directe de toute façon, ce n'est pas possible.
Edit: BTW, l'un des problèmes dans votre code (il n'y a plus de cours depuis ce que vous essayez de faire est tout simplement pas possible), c'est que vous avez passé un pointeur de fonction de type de fonction<> ce qu'elle attend est une signature. Le modèle de fonction est mis en place quelque chose comme:
Comme vous pouvez le voir, le passage d'un pointeur de fonction à ce genre de chose est tout simplement ne va pas être compris par le compilateur. Il va essayer d'instancier la déclaration de l'avant et obtenir nulle part. C'est naturellement ce que l'erreur de compilation que vous obtenez, mais il n'a pas l'adresse de votre problème fondamental, qui est que ce que vous faites ne fonctionnera jamais.
Dans un compilateur C++0x cela peut être fait différemment, mais boost::function et le MSVC on doit être comme cela. En outre, le C++0x version va avoir le même problème que vous sont actuellement confrontés.
function
etbind
pour contourner ce problème, voir par exemple stackoverflow.com/questions/2374847/... (deuxième réponse est ce qui m'a inspiré)La deuxième réponse n'a pas à passer par une C-fonction / comme un simple pointeur de fonction - c'est là que les problèmes arrivent.
Cette réponse est correcte. Je suis en train de regarder le vide* l'argument est qu'un userdata de style argument? Beaucoup de C rappels de fournir un void* pour quel que soit le contexte dont vous avez besoin. Si votre C pointeur de fonction ne prend pas en avoir une de rechange void*, alors vous ne pouvez pas faire cela.
OriginalL'auteur Crazy Eddie
Faisant l'hypothèse que la C-API permet le passage d'un type de diagnostic (dans le sens que le C-la fonction de l'API n'a pas à connaître son type, mais s'appuie sur la fonction de rappel pour savoir ce qu'il implique) paramètre de contexte (ce qui est généralement le cas avec des fonctions de rappel; dans ce cas, je soupçonne le fdata paramètre être quelque chose le long de ces lignes), passez à la fonction de l'objet dans le cadre de ce paramètre de contexte.
Il devrait alors ressembler à ceci:
Où call_callback est la C-fonction de l'API. De cette façon, vous pouvez assigner n'importe quoi que vous voulez qui prend en charge la fonction de la syntaxe d'appel de context_type::func, y compris std::tr1::bind expressions. Aussi, même si je me sens moralement obligé de le mentionner), il n'est pas, à proprement parler, défini dans la norme que les conventions d'appel C et C++ les fonctions sont les mêmes, dans la pratique, vous pourriez faire context_type un modèle de classe et de callback_relay un modèle de fonction pour faire context_type::des données plus flexible et réussir tout ce que vous voulez de cette façon.
OriginalL'auteur Anonymous Coward
Que le message d'erreur donne l'impression qu'il vous manque une inclusion d'un des types qui y participent. Au moins, essayez de double-vérifier votre
integrand
ettr1
comprend?integrand
est défini dans la Cubature.h, j'ai compris. Ce code autonome sans forme fonctionne comme il se doit,integrand
n'est pas le problèmeOriginalL'auteur Mark B
bind
fonctionne un peu différente de ce que vous supposez, je pense. Vous devez fournir une valeur, ou un espace réservé pour chaque argument.Pour votre exemple, cela revient à l' (avec espaces)
Puisque vous êtes à la liaison d'une fonction membre, vous avez un supplément (implicite) de l'argument, c'est à dire l'objet que vous appelez la fonction membre, de sorte que vous disposez de six.
Pour la première vous lier la
this
objet, pour les autres arguments, il vous suffit de passer espaces réservés.Sur une note de côté, votre membre de la fonction renvoie un double, tandis que la déclaration de la fonction renvoie void.
(pour la petite histoire, je suis toujours à l'aide d'un vieux compilateur avec peu de tr1 support, donc je n'ai que
bind
etfunction
expérience de l'utilisation de boost, peut-être que les choses ont changé un peu pour tr1...)OriginalL'auteur Pieter