Considérez les trois fonctions suivantes:
error: cannot convert âsome_function(....)::<lambda(const double&, const phase_t&)>â to ârhs_tâ {aka âEigen::Matrix<double, -1, 1> (*)(const double&, const Eigen::Matrix<double, -1, 1>&)â}
Toutes ont un argument du type rhs_t , que j'ai spécifié dans la deuxième ligne ci-dessus. De plus l'une des fonctions a un paramètre de type step_t qui dépend d'un paramètre de type rhs_t . Mon problème est que la variable que je voudrais passer à foo_ee_step , foo_int et foo_ee a le from
Eigen::MatrixXd some_function(.....):
auto better_rhs = [&c](double const & a, phase_t const & b){return my_rhs(a,b,c);};
return foo_ee(better_rhs, m);
Comme je ne peux pas changer foo_ee_step , foo_int et foo_ee j'ai essayé d'utiliser un lambda pour redéfinir la fonction de manière appropriée
phase_t my_rhs(double const &, phase_t const &, double);
mais cela se traduit par
using phase_t = Eigen::VectorXd; using rhs_t = phase_t (*)(double const &, phase_t const &); using step_t = phase_t (*)(rhs_t , phase_t const &, double, double); Eigen::MatrixXd foo_ee_step(rhs_t rhs, phase_t const &z0); Eigen::MatrixXd foo_int(step_t step, rhs_t rhs, phase_t const & z0); Eigen::MatrixXd foo_ee(rhs_t rhs, phase_t const &z0);
Je pense que cela vient du fait que j'essaye de passer un lambda qui capture quelque chose comme un pointeur de fonction, ce qui semble être interdit ... J'ai lu ici , que l'on pourrait essayer de résoudre ce problème en définissant un foncteur. Mais si je ne me trompe pas, pour que cela fonctionne, j'aurais besoin de changer foo_ee_step , foo_int et foo_ee , ce que je ne peux pas. Soo, je ne sais pas vraiment comment aborder ce problème .. Est-il possible de convertir cette expression lambda sous la forme rhs_t ? Existe-t-il d'autres techniques pour résoudre ce problème?
P.S. Je ne sais pas si c'est important, mais jusqu'à présent, j'ai aussi essayé:
some_function qui est nommée better_rhs (qui évidemment n'a pas non plus fonctionné). foo_ee_step , etc. comme fonctions membres. Ensuite, définissez simplement une autre fonction membre better_rhs et appelez-la my_rhs .. Cela provoquait une erreur concernant l'impossibilité de passer une fonction membre non statique, mais le fait de devoir l'appeler explicitement ... Toute indication sur la façon de procéder est appréciée.
3 Réponses :
Habituellement, les fonctions externes qui prennent des pointeurs de fonction prennent également un pointeur de données void * et peuvent donc transmettre un contexte supplémentaire (ce qui dans votre cas serait un pointeur vers un double). Sans cela, la fonction n'est tout simplement pas appelée avec suffisamment de données.
Vous pouvez essayer un double statique comme:
static double data;
data = c;
return foo_ee([](double const& a, phase_t const& b) { return my_rhs(a, b, data); }, m);
Mais ce n'est pas thread-safe (Et Je ne sais pas comment la fonction passée est appelée, mais l'exécuter une deuxième fois ferait pointer l'ancien pointeur de fonction vers les nouvelles données, probablement pas ce que vous voulez).
Peut-être phase_t contient ce pointeur de contexte?
Vous pouvez stocker c dans une variable globale, ou une variable statique dans une fonction get_global_c , et référencer cela dans votre lambda, vous n'avez donc pas à capturer il:
// ...
static double c;
void some_function()
{
// ...
c = calculate_c();
auto better_rhs = [](double const &a, phase_t const &b) { return my_rhs(a, b, c); };
rerturn foo_ee(better_rhs, m);
}
Les seuls moyens de le faire sont plutôt piratés. Vous devez réaliser qu'un pointeur de fonction n'est qu'un pointeur vers un emplacement de mémoire statique où se trouve une fonction. Par conséquent, l'ajout d'un état (c'est-à-dire la liaison du paramètre double supplémentaire) avec une durée de stockage dynamique ou automatique (données de tas ou de pile) n'est pas possible. La fonction aurait besoin de maintenant où cela vit, mais elle ne le peut pas. (C'est la raison pour laquelle les interfaces de fonction génériques en C prennent un void * et un pointeur de fonction prenant également un void * , de sorte que l'emplacement de l'état est passé comme un pointeur vers void et puis interprété au bon type dans la fonction)
Vous pouvez ajouter un état avec une durée de stockage statique, donc c'est à dire de la manière suivante:
// Interface we want to match
void print_call(int (*f)()) {
std::cout << f() << `\n`;
}
// Way 1: Globals
static int data = 0;
int get_data() { return data; }
print_call(get_data); // Prints 0
data = 42;
print_call(get_data); // Prints 42
// Way 2: Class statics
struct state {
int data = 0;
static int get_data() { return data; }
};
print_call(state::get_data); // Prints 0
state::data = 42;
print_call(state::get_data); // Prints 42
Je préférerais la voie 2 pour des raisons d'encapsulation et un ordre d'initialisation plus compréhensible.
Notez que l'utilisation de la statique pose ses propres problèmes. Vous voudrez peut-être vérifier si vous ne pouvez pas changer votre conception d'une manière ou d'une autre pour vous débarrasser de tout le problème.