3 votes

Cast entre les pointeurs de fonction

Je suis en train de mettre en place un système de minuterie/callback en utilisant les fastdelegates de Don Clugston. (voir http://www.codeproject.com/KB/cpp/FastDelegate.aspx )

Voici le code de départ :

struct TimerContext
{
};

void free_func( TimerContext* )
{
}

struct Foo
{
    void member_func( TimerContext* )
    {
    }
};

Foo f;
MulticastDelegate< void (TimerContext*) > delegate;

delegate += free_func;
delegate += bind( &Foo::member_func, &f );

D'accord, mais maintenant, je souhaite que l'utilisateur puisse sous-classer TimerContext de stocker et d'envoyer ses propres structures aux rappels. L'objectif est ici d'éviter à l'utilisateur d'avoir à descendre la balise TimerContext lui-même

struct TimerContext
{
};

struct MyTimerContext : TimerContext
{
    int user_value;
};

void free_func( TimerContext* )
{
}

void free_func2( MyTimerContext* )
{
}

struct Foo
{
    void member_func( TimerContext* )
    {
    }

    void member_func2( MyTimerContext* )
    {
    }
};

Foo f;
MulticastDelegate< void (TimerContext*) > delegate;

delegate += free_func;
delegate += free_func2;
delegate += bind( &Foo::member_func,  &f );
delegate += bind( &Foo::member_func2, &f );

Comme vous l'avez deviné, GCC ne me permet pas de le faire :)

error: invalid conversion from `void (*)(MyTimerContext*)' to `void (*)(TimerContext*)'
error:   initializing argument 1 of `delegate::Delegate<R ()(Param1)>::Delegate(R (*)(Param1)) [with R = void, Param1 = TimerContext*]'

Ma question est donc la suivante : Si je force la distribution en utilisant reinterpret_cast Le système fonctionnera, mais sera-t-il sûr ?

PS : Il s'agit de rappels critiques en termes de temps, les solutions lourdes orientées vers le virtuel sont considérées comme impraticables :/

5voto

Kirill V. Lyadvinsky Points 47627

La norme C++ stipule dans la section 13.4/7 que :

il n'existe pas de conversion standard (clause 4) d'un type de pointeur vers une fonction en un autre type. En particulier, même si B est une base publique de D , nous avons

D* f();
B* (*p1)() = &f;  // error
void g(D*);
void (*p2)(B*) = &g;  // error

Vous pouvez néanmoins utiliser l'adaptateur de fonction pour stocker des pointeurs vers des fonctions à un seul argument, quelque chose comme boost::function mais je ne suis pas sûr que cela puisse résoudre votre problème.

0voto

sellibitze Points 13607

Bien entendu, le moulage des pointeurs de fonction est généralement une mauvaise idée.

Casting d'un pointeur de fonction de void(*)(Derived*) a void(*)(Base*) peut fonctionner ou non. Cela ne fonctionnera certainement pas si la représentation interne des pointeurs Derived* et Base* doit être ajustée lors de la conversion. Cependant, dans le cas de votre relation d'héritage unique, cela est peu probable. Cependant, la disposition des classes et les ajustements de pointeurs sont définis par l'implémentation et vous ne devez pas vous y fier. Si vous voulez prendre le risque : Allez-y avec ahread.

En supposant que les pointeurs n'ont pas besoin d'être ajustés, une conversion de void(*)(Derived1*) a void(*)(Base*) ne serait toujours pas une bonne idée (non sécurisée) parce qu'elle permet à une fonction qui attend un Derived1* d'être appelée avec un Derived2* où Derived1 et Derived2 sont frères et sœurs dans la hiérarchie de l'héritage.

0voto

xtofl Points 22333

reinterpret_cast n'est sûr que si l'"émetteur" et le "récepteur" de l'objet correspondent. Ainsi, si l'émetteur et le récepteur sont implémentés par le même morceau de code, la sécurité peut être assurée pendant un certain temps.

Si vous souhaitez ajouter des rappels à un délégué, y vous voulez qu'ils aient un type différent, comme vous le faites, vous avez deux scénarios :

  • vous connaissez tous les délégués à l'avance, au moment de la compilation => vous pouvez les envelopper dans une liste de types.

  • peuvent être constitués au moment de l'exécution => vous devez utiliser la liaison au moment de l'exécution, c'est-à-dire les fonctions virtuelles ( un exec ou autre).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X