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

Langage C++ Discussion :

Pointeur dans un template


Sujet :

Langage C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut Pointeur dans un template
    Bonjour,

    J'ai le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template<class CLASS>
    class A
    {
    	CLASS* owner;
    public:
    	A(CLASS* that)
    	{
    		owner = that;
    	};
    	~A(void){};
    };
    cela compile et je l'execute avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class B
    {
    void Run(){ A<B> a(this); }
    };
    Le problème est que mon pointeur owner reste un pointeur sur rien après l'instruction owner = that;

    Quelqu'un aurait une idée du problème?

    Merci

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Va falloir un peu plus de code. Car dans le code que tu proposes, ce n'est pas le cas (en mode debug).

    P.S. CLASS comme nom d'un type paramétrique me semble une mauvaise idée : ça ressemble trop au mot clé class.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Mon problème n'a semble t'il rien à voir avec le template (le code du premier post fonctionne très bien)

    En fait j'essaie de faire un callback sur un membre d'instance en environnement multi thread. Et a priori c'est le multi thread qui pose problème.

    Voici le template du callback:
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    template<class CLASS, typename RET = void, typename ARG = void>
    class Callback
    {
    private:
    	typedef RET (CLASS::*Function)(ARG);
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function, CLASS* that)
    	{
    		this->function = function;
    		this->owner = that;
    	};
     
    	~Callback(void){};
     
    	RET operator()(ARG a) { return call(a); };
     
    	RET call(ARG a) { return (owner->*function)(a); };
    };
     
     
    template<class CLASS, typename RET>
    class Callback<CLASS, RET, void>
    {
    private:
    	typedef RET (CLASS::*Function)();
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function, CLASS* that)
    	{
    		this->function = function;
    		this->owner = that;
    	};
     
    	~Callback(void){};
     
    	RET operator()() { return call(); };
     
    	RET call() { return (owner->*function)(); };
    };
    L'instance de classe qui a la fonction à rappeler est multithread, ci dessous le code un peu simplifié.
    La fonction Request est statique
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    RemoteControlServer* RemoteControlServer::currentInstance = NULL;
    HANDLE RemoteControlServer::threadHandle = NULL;
     
    void  RemoteControlServer::Request()
    {
    	if(currentInstance == NULL)
    		currentInstance = new RemoteControlServer();
    	currentInstance->Start();
    }
     
    void RemoteControlServer::Run()
    {
    	RemoteControlComWrapper* remoteControlComWrapper = new RemoteControlComWrapper();
    	remoteControlComWrapper->DisplayApproval(&Callback<RemoteControlServer>(&RemoteControlServer::OnApprovalAccepted, this));
    }
    void RemoteControlServer::OnApprovalAccepted()
    {printf("Yeeeesss!!");}
     
    DWORD WINAPI  RemoteControlServer::ThreadStart(void* param)
    {
        RemoteControlServer* This = (RemoteControlServer*) param;
    	This->Run();
        return true;
    }
     
    void RemoteControlServer::Start()
    {
    	if(threadHandle != NULL) CloseHandle(threadHandle);
     
    	threadHandle = ::CreateThread(NULL, 0, RemoteControlServer::ThreadStart, (void*)this, 0, NULL);
    	if(threadHandle == NULL)
    	{
    		//
    	}
     
    	SetThreadPriority(threadHandle, THREAD_PRIORITY_LOWEST);
     
    	 WaitForSingleObject(threadHandle, INFINITE);
    }
    Notez que ce code fonctionne (le callback est bien appelé), pour le moment je n'arrive pas à reproduire le problème de mon projet dans un projet plus simple.

    Dans mon projet, la seule chose que j'ai trouvée est que l'égalité de pointeur dans la création de callback : this->owner = that; fonctionne si dans l'appel du constructeur, je remplace this par currentInstance.
    Mais le callback ne fonctionne pas pour autant

    Avez vous des pistes d'exploration à me donner?
    Qu'est ce qui peut empêcher de mettre un pointeur dans un autre?

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    remoteControlComWrapper->DisplayApproval(&Callback<RemoteControlServer>(&RemoteControlServer::OnApprovalAccepted, this));Tu prends l'adresse d'un objet détruit dès la sortie de la fonction => comportement indéterminé ! Ce qui explique que ça peut avoir l'air de marcher en single thread mais pas en multithread.

    Deux remarques :
    1/ un wrapper comme Callback serait plutôt à manipuler par valeur et non par pointeur.

    2/ T'as entendu parler de tr1/std/boost::function et tr1/std/boost::bind ou tu es un fan du NIH

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Tu prends l'adresse d'un objet détruit dès la sortie de la fonction
    Détruit aprsè quelle fonction?DisplayApproval ou le constructeur de Callback?

    Ce qui explique que ça peut avoir l'air de marcher en single thread mais pas en multithread.
    La création du callback et l'appel de la méthode callback est exécuter dans le même thread, le seul problème que je vois est que this est créé dans un thread et qu'il est passé en paramètre au callback dans un autre thread. Mais je vois pas ou est le problème


    1/ un wrapper comme Callback serait plutôt à manipuler par valeur et non par pointeur
    Je vais regardé ça....

    2/ T'as entendu parler de tr1/std/boost::function et tr1/std/boost::bind ou tu es un fan du NIH
    Ouais vaguement... je voulais juste faire quelque chose de simple et que je maitrise, mais c'est pas du tout le cas

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Arfff! je comprends rien!!!
    J'ai supprimé toute notion de multithread dans mon test.
    Je crée le callback en dehors de la classe, cela fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A a;
    Callback<A> mycall(&A::OnApprovalAccepted, &a);
    a.Test(mycall);
    Je fais la même chose(ie création du callback), à l'intérieur de la classe A, cela ne fonctionne pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void A::Run()
    {
    	Callback<A> mycall(&A::OnApprovalAccepted, this);
    	Test(mycall);
    }
    J'ai une erreur "Violation d'accès 0xbiduletrucmachinchose" à l'appel de la fonction du callback:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (owner->*function)();
    As tu une explication?

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Montres-nous Test.

    La solution (surtout si c'est du pro) reste quand même de s'appuyer sur du boost::function/bind (ou tr1 ou std selon les compilo visés)

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Voilà la function test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void A::Test(Callback<A> onApprovalAccepted)
    {
    	onApprovalAccepted.call();
    }
    et la function call de la classe Callback
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    RET Callback::call() 
    { 
    	return (owner->*function)(); 
    }

    La solution (surtout si c'est du pro) reste quand même de s'appuyer sur du boost::function/bind (ou tr1 ou std selon les compilo visés)
    Ok, mais j'aimerai comprendre pourquoi ça marche pas (j'ai ma p'tite fierté quand même )

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    template<class CLASS, typename RET = void, typename ARG = void>
    class Callback
    {
    private:
    	typedef RET (CLASS::*Function)(ARG);
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
     
    	~Callback(void){};
     
    	RET operator()(ARG a) { return call(a); };
     
    	RET call(ARG a) { return (owner->*function)(a); };
    };
     
     
    template<class CLASS, typename RET>
    class Callback<CLASS, RET, void>
    {
    private:
    	typedef RET (CLASS::*Function)();
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
     
    	RET operator()() { return call(); };
     
    	RET call() { return (owner->*function)(); };
    };
     
    #include <iostream>
    struct A
    {
        void OnApprovalAccepted()
        {
            std::cout<<"OnApprovalAccepted\n";
        }
     
        static void Test(Callback<A> onApprovalAccepted)
        {
            onApprovalAccepted();
            onApprovalAccepted.call();
        }
     
        void Run()
        {
            Callback<A> mycall(&A::OnApprovalAccepted, this);
            Test(mycall);
        }
     
    };
     
    void test1()
    {
        A a;
        Callback<A> mycall(&A::OnApprovalAccepted, &a);
        A::Test(mycall);
    }
     
    void test2()
    {
        A a;
        a.Run();
    }
     
    int main()
    {
        test1();
        test2();
     
        return 0;
    }
    Ca fonctionne. Donc il manque du code pour reproduire ton problème

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Effectivement, ton code fonctionne. et je m'arrache les cheveux pour reproduire mon problème

    Avec le code suivant tu devrais pouvoir le reproduire.
    Si je décommente la ligne dans A::Test(Callback<A> onAcceptedCallback), ça fonctionne et si je commente ça fonctionne pas... pourtant la méthode n'est pas appelée


    Fichier a.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #pragma once
    #include "B.h"
    #include "Callback.h"
     
    class A
    {
    public:
    	A(void);
    	~A(void);
    	void Run();
    	void Test(Callback<A> onAcceptedCallback);
    	void OnAccepted();
    };
    fichier a.cpp
    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
    29
    30
    31
     
    #include "StdAfx.h"
    #include "A.h"
    #include "B.h"
    #include "Callback.h"
     
    A::A()
    {
    }
     
    A::~A(void)
    {
    }
     
    void A::Run()
    {
    	B b;
    	Callback<A> mycall(&A::OnAccepted, this);
    	b.Display(mycall);
    }
     
    void A::Test(Callback<A> onAcceptedCallback)
    {
    	// Ligne à commenter ou décommenter
    	//onAcceptedCallback();
    }
     
    void A::OnAccepted()
    {
    	printf("OnAccepted");
    }
    fichier b.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #pragma once
     
    template<class CLASS, typename RET = void, typename ARG = void>
    class Callback;
    class A;
     
    class B
    {
    public:
    	B();
    	~B();
    	void Display(Callback<A> onAccepted);
    };
    fichier b.cpp
    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
     
    #include "stdafx.h"
    #include "B.h"
    #include "Callback.h"
     
    B::B()
    {
     
    }
     
    B::~B(void)
    {
    }
     
     
    void B::Display(Callback<A> onAccepted)
    {
    	onAccepted.call();
    }
    main
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int _tmain(int argc, _TCHAR* argv[])
    {
    	A a;
        a.Run();
    	return 0;
    }

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    ça marche
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    template<class CLASS, typename RET=void, typename ARG = void>
    class Callback;
    class A;
     
    class B
    {
    public:
    	B();
    	~B();
    	void Display(Callback<A> onAccepted);
    };
     
    template<class CLASS, typename RET, typename ARG>
    class Callback
    {
    private:
    	typedef RET (CLASS::*Function)(ARG);
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
     
    	~Callback(void){};
     
    	RET operator()(ARG a) { return call(a); };
     
    	RET call(ARG a) { return (owner->*function)(a); };
    };
     
    template<class CLASS, typename RET>
    class Callback<CLASS, RET, void>
    {
    private:
    	typedef RET (CLASS::*Function)();
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
     
    	RET operator()() { return call(); };
     
    	RET call() { return (owner->*function)(); };
    };
     
    B::B()
    {
     
    }
     
    B::~B(void)
    {
    }
     
     
    void B::Display(Callback<A> onAccepted)
    {
    	onAccepted.call();
    }
     
    class A
    {
    public:
    	A(void);
    	~A(void);
    	void Run();
    	void Test(Callback<A> onAcceptedCallback);
    	void OnAccepted();
    };
     
    A::A()
    {
    }
     
    A::~A(void)
    {
    }
     
    void A::Run()
    {
    	B b;
    	Callback<A> mycall(&A::OnAccepted, this);
    	b.Display(mycall);
    }
     
    void A::Test(Callback<A> onAcceptedCallback)
    {
    	// Ligne à commenter ou décommenter
    	onAcceptedCallback();
    }
     
    #include <iostream>
    void A::OnAccepted()
    {
    	std::cout<<"OnAccepted\n";
    }
     
    int main()
    {
    	A a;
        a.Run();
        a.Test(Callback<A>(&A::OnAccepted, &a));
    	return 0;
    }

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Effectivement, ça marche si on met tout le code dans le même fichier cpp.
    Mais peux tu essayer de créer les fichiers B.h B.cpp A.h A.cpp et Callback.h comme indiqué dans mon post précédent.

    Merci pour ton aide et le temps que tu passes pour m'aider à comprendre ce ?!?%*/ de problème

  13. #13
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Code a.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #pragma once
     
    #include "B.h"
    #include "Callback.h"
     
    class A
    {
    public:
    	A(void);
    	~A(void);
    	void Run();
    	void Test(Callback<A> onAcceptedCallback);
    	void OnAccepted();
    };

    Code a.cpp : 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
    29
    30
    #include "A.h"
    #include "B.h"
    #include "Callback.h"
    #include <cstdio>
     
    A::A()
    {
    }
     
    A::~A(void)
    {
    }
     
    void A::Run()
    {
    	B b;
    	Callback<A> mycall(&A::OnAccepted, this);
    	b.Display(mycall);
    }
     
    void A::Test(Callback<A> onAcceptedCallback)
    {
    	// Ligne à commenter ou décommenter
    	//onAcceptedCallback();
    }
     
    void A::OnAccepted()
    {
    	printf("OnAccepted\n");
    }

    Code b.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #pragma once
     
    template<class CLASS, typename RET = void, typename ARG = void>
    class Callback;
    class A;
     
    class B
    {
    public:
    	B();
    	~B();
    	void Display(Callback<A> onAccepted);
    };

    Code b.cpp : 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
    #include "B.h"
    #include "Callback.h"
    #include "a.h"
     
    B::B()
    {
     
    }
     
    B::~B(void)
    {
    }
     
     
    void B::Display(Callback<A> onAccepted)
    {
    	onAccepted.call();
    }

    Code callback.h : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #pragma once
    template<class CLASS, typename RET=void, typename ARG=void>
    class Callback
    {
    private:
    	typedef RET (CLASS::*Function)(ARG);
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
     
    	~Callback(void){};
     
    	RET operator()(ARG a) { return call(a); };
     
    	RET call(ARG a) { return (owner->*function)(a); };
    };
     
     
    template<class CLASS, typename RET>
    class Callback<CLASS, RET, void>
    {
    private:
    	typedef RET (CLASS::*Function)();
    	Function function;
    	CLASS* owner;
    public:
    	Callback(Function function_, CLASS* that)
    	:function(function_),owner(that)
    	{}
        ~Callback()
        {
            owner = reinterpret_cast<CLASS*>(0xFFFFFFFF);
        }
     
    	RET operator()()
       {
           return call();
       };
     
    	RET call()
       {
           return (owner->*function)();
       };
    };

    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include "a.h"
     
    int main()
    {
    	A a;
        a.Run();
    	return 0;
    }

    Tout est encore ok avec visual 2008, 2010, Mingw (4.5.2) C++2003, Mingw C++0x aussi bien en debug qu'en release

    La vérité est ailleurs

    Qu'utilises-tu comme compilateur ? Avec quelles options ?

    Peux-tu poster un zip contenant un projet minimal qui bug chez toi ?

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Sous VS2008
    test.zip

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Bon,
    La seule explication que je trouve est la suivante :
    dans b.cpp :
    Code b.cpp : 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
    #include "stdafx.h"
    #include "B.h"
    #include "Callback.h"
     
     
    B::B()
    {
     
    }
     
    B::~B(void)
    {
    }
     
     
    void B::Display(Callback<A> onAccepted)
    {
    	onAccepted.call();
    }
    L'appel de onAccept.call() :RET call() { return (owner->*function)(); };Ici on a l'appel d'un pointeur membre function sur un pointeur owner dont le type A est incomplet. En effet, si on parse le fichier B.cpp, on se rend compte que oui on a fait une déclaration anticipée class A; dans B.h, mais vue de B.cpp, on n'a jamais défini la classe A.
    Or la norme nous dit que le déréférencement d'un pointeur membre doit se faire sur un type complètement défini :
    Citation Envoyé par 5.5. member operators
    The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” (where T is a completely-defined class type) to its first operand, which shall be of type “pointer to T” or “pointer to a class of which T is an unambiguous and accessible base class.” The result is an object or a function of the
    type specified by the second operand.
    Il faut donc définir A dans B.cpp et d'ailleurs cela supprime le problème instantanément :
    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
    #include "stdafx.h"
    #include "B.h"
    #include "Callback.h"
    #include "A.h"
     
    B::B()
    {
     
    }
     
    B::~B(void)
    {
    }
     
     
    void B::Display(Callback<A> onAccepted)
    {
    	onAccepted.call();
    }
    Le problème se reproduit avec ce code minimal :
    Code a.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class A;
    typedef void (A::*p_function)();
    A *get_a_A();
    p_function get_a_func_of_A();

    Code a.cpp : 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
    #include "A.h"
     
    class A
    {
    public:
        void dummy()
        {
        }
    };
    A a;
     
    A *get_a_A()
    {
        return &a;
    }
     
    p_function get_a_func_of_A()
    {
        return &A::dummy;
    }

    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "a.h"
     
    void call_it(p_function func_,A*pa_)
    {
        (pa_->*func_)();
    }
     
     
    int main()
    {
        call_it(get_a_func_of_A(),get_a_A());
    	return 0;
    }

    Boum, erreur garantie.


    Ce qui me surprend, c'est qu'à la lecture de la norme, les compilateurs devraient jeter une erreur lors de l'appel (pa_->*func_)();Or j'ai testé 7 compilateurs différents[*], aucun compilateur ne me lève d'erreur. MinGW donne même du code fonctionnel (Visual plante comme on le voit, mais j'ai pas tenté l'exécution avec les autres compilateurs).

    Conclusion :
    L'opérateur ->* (ou .*) nécessite que le type de gauche soit complètement défini.

    Conclusion 2:
    Utilises boost/std/tr1::function et bind.
    [*] pas cherché s'ils s'appuient sur le même frontend

  16. #16
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 208
    Par défaut
    Ok!!

    Merci beaucoup pour ton aide et tes explications claires

    Ce genre de problème ça donne tout de suite envie de faire du C++

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

Discussions similaires

  1. Libération de pointeurs dans un std::vector
    Par G dans le forum SL & STL
    Réponses: 17
    Dernier message: 06/04/2005, 22h37
  2. Réponses: 2
    Dernier message: 15/11/2004, 15h12
  3. cast dans un template
    Par olivic dans le forum Langage
    Réponses: 15
    Dernier message: 20/10/2004, 14h10
  4. Utilisation de Pointeurs dans API windows
    Par Drooxy dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 13/03/2003, 22h39
  5. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14

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