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 sur donnée membre


Sujet :

Langage C++

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut pointeur sur donnée membre
    Bonjour tout le monde

    J'espere que le pere noël a été sympa avec vous

    Je developpe une appli qui charge des données typées (depuis une BdD). Je souhaiterai créer un framework qui permet de simplifier au max le travail de l'utilisateur de ce framework.

    J'ai donc commencer par me créer une class Value :
    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
    struct NoCheckValidator
    {
    	template <typename T>
    	static bool Check(const T& /*value*/)
    	{
    		return true;
    	}
    };
     
    template <typename T, typename C, typename V = NoCheckValidator>
    class Value
    {
    public:
    	typedef T value_t;
    	typedef C convert_functor;
    	typedef V validator_t;
     
    private:
    	value_t   m_value;
     
    public:
    	Value(const value_t& v = value_t())
    	: m_value(v)
    	{
    	}
     
    	Value(wxSQLite3ResultSet& res, const wxString& colName, const value_t& defaultValue = value_t())
    	{
    		load(res, colName, defaultValue);
    	}
     
    	virtual ~Value()
    	{
    	}
     
    	const value_t& operator()() const 
    	{
    		return m_value;
    	}
     
    	bool operator()(const value_t& v) 
    	{
    		return set(v);
    	}
     
    	bool load(wxSQLite3ResultSet& res, const wxString& colName, const value_t& defaultValue = value_t())
    	{
    		return set( convert_functor::load(res, colName, defaultValue) );
    	}
     
    protected:
    	bool set(const value_t& v)
    	{
    		if (validator_t::Check(v) == false) {
    			return false;
    		}
    		m_value = v;
    		return true;
    	}
    };
    Je peux donc créer des types de valeur, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct int_converter
    {
    	static
    	int load(wxSQLite3ResultSet& res, const wxString& colName, int defaultValue)
    	{
    		return res.GetInt(colName, defaultValue);
    	}
    };
    typedef Value<int, int_converter>    integer;
    A présent, je peux donc me créer des classes contenant ces Value :
    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
    class Cost : public db::Table
    {
    public:
    	db::real   unit_cost;
    	db::real   quantity;
    	db::text   name;
    	db::date   date;
    	db::ID     id_task;
     
    	static const wxString TABLE_NAME;
     
    public:
    	Cost();
    	Cost(wxSQLite3ResultSet& res);
     
    	double cost() const { return unit_cost() * quantity(); }
     
    	// DB
    	virtual db::update_value_type prepare_insert(wxSQLite3Database& db);
    	virtual db::update_value_type prepare_update(wxSQLite3Database& db);
    };
    Avec ceci, je suis tout de même obligé de charger dans le constructeur qui possede le resultat de la requete, l'ensemble des variables. Ce que j'aimerai, c'est pouvoir créer une variable static, permettant de connaitre les variables et donc de les charger automatiquement dans la classe de base (db::Table dans mon cas). Un truc du genre :

    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
    template <typename T>
    class Table
    {
        static ColumnsContainer m_columns; // oui mais quoi ?
        ...
     
        bool load(...); // il ferait tout
    };
     
    bool Table::load(...)
    {
        BOOST_FOREACH(var, m_columns) {
            var.load(...);
        }
    }
     
    class Cost : public Table<Cost>
    {
        ...
    }
     
    Table<Cost>:: ColumnsContainer Table<Cost>::m_columns = { &Cost::name, ... }; // un truc a base de boost::assign
    // ou mieux, avec un define
    DEFINE_DB_VARS_nn(Cost, name, ...); // avec nn parametres
    Je comprends qu'on ne peut pas créer un pointeur sur une variable membre sans avoir instancié l'objet, mais y a t il une solution à ce que je souhaite ?
    Jérémie

  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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Je ne vais pas répondre directement à ta question mais sait-on jamais...
    En général, lorsque j'ai des objets complexes, ils ne se construisent pas tout seul. J'utilise ce qui ressemble à un DP builder qui est ami de la classe à construire. Peut être est-ce une solution à ton problème ?

  3. #3
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Si j'ai bien compris, tu cherches à faire un mapping entre la base de données et des classes C++. En C++, les types sont statiques, donc un tel mapping ne peut pas être résolu à l'exécution.

    Du coup, je ne suis pas sûr que l'approche par template soit la plus pertinente...

  4. #4
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Salut

    Citation Envoyé par 3DArchi Voir le message
    En général, lorsque j'ai des objets complexes, ils ne se construisent pas tout seul. J'utilise ce qui ressemble à un DP builder qui est ami de la classe à construire.
    Je ne connais pas ce principe, et google ne m'a pas fourni de lien avec "DP Builder". Peux tu me donner plus d'infos ?

    En C++, les types sont statiques, donc un tel mapping ne peut pas être résolu à l'exécution.
    Tout a fait, mais ce n'est pas ce que je cherche à faire. Je cherche simplement (?) à simplifier la création d'objet mappant une table, sachant que l'utilisateur doit connaitre les colonnes et leurs type.

    Pour reprendre le code précedent :

    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
    template <typename T>
    class Table
    {
        static ColumnsContainer m_columns; // oui mais quoi ?
        ...
     
        bool load(...); // il ferait tout
    };
     
    bool Table::load(...)
    {
        BOOST_FOREACH(var, m_columns) {
            var.load(...);
        }
    }
     
    class Cost : public Table<Cost>
    {
    public:
        db::integer  int_value;
     
     
    }
     
    // Definir le lien entre un nom de colonne et une variable
    Table<Cost>:: ColumnsContainer Table<Cost>::m_columns = { (&Cost::name, "name", ... }; // un truc a base de boost::assign
    // ou mieux, avec un define
    // ou name represente le nom de la variable membre et "name" represente le nom de la colonne
    DEFINE_DB_VARS_nn(Cost, (name, "name", ...); // avec nn colonnes
    Peut être n'est ce pas possible...
    Jérémie

  5. #5
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    DP Builder.
    Au départ, j'ai eu envie d'appliquer un type erasure sur Value :
    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
    struct value_base
    {
        virtual ~value_base()=default;
    };
     
    template<class T>
    struct value : public value_base
    {
        T value;
    };
     
    template <typename T>
    class Table
    {
        struct ColumnsContainer
        {
            std::pair<std::string,value_base T::*> elt;
        };
     
        static ColumnsContainer m_columns; // oui mais quoi ?
    };
     
     
    class Cost : public Table<Cost>
    {
    public:
        value<int>  int_value;
    };
     
    // Definir le lien entre un nom de colonne et une variable
    template<>
    Table<Cost>::ColumnsContainer Table<Cost>::m_columns = {{"name", &Cost::int_value} }; // un truc a base de boost::assign
    mais ça ne marche pas
    invalid conversion from 'value<int> Cost::*' to 'value_base Cost::*'
    J'ai l'impression que la piste est par là, mais peut être en ne prenant pas en compte un value mais un contructeur de value hors de la classe ?

  6. #6
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Tout a fait, mais ce n'est pas ce que je cherche à faire. Je cherche simplement (?) à simplifier la création d'objet mappant une table, sachant que l'utilisateur doit connaitre les colonnes et leurs type.
    Pour les types des colonnes, je pense à un tuple (il y a ça dans boost). Pour les noms des colonnes, un enum. Pourquoi un enum plutôt qu'une chaîne ? Parce que si, de toute manière, ça doit être connu à la compilation, autant utiliser les possibilités de vérification que nous donne l'utilisation d'un enum.

    Auquel cas, l'utilisateur n'aurait plus qu'à écrire quelque chose du genre :

    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
    class ExampleTableParameters
    {
        typedef tuple<int, double, std::string> ColumnsType;
        enum Column {
            Id = 0,
            Amount = 1,
            Comment = 2
        };
        static Column GetIndex(std::string columnName)
        {
            if(columnName == "Id")
                return Id;
            ...
        }
     
        static std::string GetColumnName(Column idx)
        {
             switch(idx)
             {
                 case Id: return "Id";
                 case Amount : return "Amount";
                 ...
             }
        }
    };
     
    class ExampleTable : GenericTable<ExampleTableParameters>
    { // rien à faire à priori
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<typename Parameters> class GenericTable
    {
    ...
    }
    De ton côté, tu as le plus gros du boulot dans GenericTable :

    - stocker les valeurs en utilisant le tuple (et donc, fournir les diverses conversions pour initialiser correctement chacune des valeurs du tuple avec les valeurs lues depuis la base).
    - fournir une méthode GetValue(Parameters::Column). Je ne crois pas que tu puisses t'en sortir autrement qu'avec un gros switch sur la valeur pour repasser du runtime au compile-time, ce qui induit malheureusement une limite sur le nombre de colonnes (si ça peut te rassurer, il me semble que tu as déjà cette limite à cause de tuple, donc tu ne la rajoutes pas).
    - fournir une méthode (renvoyant un variant) GetValue(std::string const & columnName), qui utilise Parameters::GetColumnIndex et GetValue(Parameters::Column).

    Ensuite, il me semble intéressant de rajouter quelques politiques au niveau du chargement des données, du cache, etc (on ne veut pas nécessairement charger toute la table en mémoire).

  7. #7
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Salut, et merci pour les pistes que vous proposez

    Citation Envoyé par 3DArchi Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    invalid conversion from 'value<int> Cost::*' to 'value_base Cost::*'
    J'ai l'impression que la piste est par là, mais peut être en ne prenant pas en compte un value mais un contructeur de value hors de la classe ?
    Mince alors, je n'avais même pas testé car pour moi un pointeur sur une variable membre ne signifie rien. Pour une méthode, ca me parait logique : c'est l'@ du début de la méthode, que l'on peut observer sans instancier d'objet. Mais une variable n'a pas d'@ sans instanciation d'un objet ! la notion &Classe::variable ne peut exister.

    Le coup de switch / case sur des enum ne semble pas simplifier le travail de l'utilisateur, qui va devoir faire plus d'un coté pour en faire moins de l'autre...
    Jérémie

  8. #8
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par jfouche Voir le message
    Mais une variable n'a pas d'@ sans instanciation d'un objet ! la notion &Classe::variable ne peut exister.
    Tu peux voir ça un peu comme un offset sur l'adresse de l'objet qui sera donné pour utiliser le pointeur. En fait, avec une fonction membre le problème peut se poser : quelle adresse pour une fonction membre virtuelle ? (teasing : la réponse très bientôt).

  9. #9
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Salut

    Merci pour les explications. Pour répondre à la questions sur les méthodes virtuelles, je me rends compte que je ne saurais dire... Peut être la table des méthodes virtuelles (vtable) ?
    Sinon, je ne vois pas vraiment de solutions à mon pb comme ça. Une idée serai peut etre d'avoir des variables membre sous forme de pointeur, ce qui permettrai sans doute de pouvoir faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct ColumnsContainer
    {
        std::map<wxString, value_base* T::*> elt;
    };
    et de passer outre l'erreur du compilateur (on peut caster sans pb un Derived* en Base*). Par contre, ça m'embete un peu : ça m'oblige à bosser un peu pour gérer cela

    Merci pour toutes ces explications, et si tu as une idée, n'hésites pas.

    edit : J'ai tenté le code suivant (un peu gros, mais complet) :
    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    #include <iostream>
    #include <string>
    #include <map>
    #include <boost/assign/list_of.hpp>
     
    using namespace std;
    using namespace boost::assign;
     
    struct NoCheckValidator
    {
    	template <typename T>
    	static bool Check(const T& /*value*/)
    	{
    		return true;
    	}
    };
     
    class ValueBase
    {
    public:
    	virtual bool load(const string& colName) = 0;
    };
     
    template <typename T, typename C, typename V = NoCheckValidator>
    class Value
    {
    public:
    	typedef T value_t;
    	typedef C convert_functor;
    	typedef V validator_t;
     
    private:
    	value_t   m_value;
     
    public:
    	Value(const value_t& v = value_t())
    	: m_value(v)
    	{
    	}
     
    	Value(const string& colName)
    	{
    		load(colName);
    	}
     
    	virtual ~Value()
    	{
    	}
     
    	const value_t& operator()() const 
    	{
    		return get();
    	}
     
    	bool operator()(const value_t& v) 
    	{
    		return set(v);
    	}
     
    	virtual bool load(const string& colName)
    	{
    		return set( convert_functor::load(colName) );
    	}
     
    protected:
    	const value_t& get() const 
    	{
    		return m_value;
    	}
     
    	bool set(const value_t& v)
    	{
    		if (validator_t::Check(v) == false) {
    			return false;
    		}
    		m_value = v;
    		return true;
    	}
    };
     
    struct int_converter
    {
    	static int load(const string& colName)
    	{
    		return 1;
    	}
    };
     
    typedef Value<int, int_converter> integer;
     
    class Object
    {
    protected:
        Object() { }
    	virtual ~Object() { }
     
    public:
    	virtual bool load() = 0;
    };
     
    template <class T>
    class Table : public Object
    {
    	typedef map<string, ValueBase* T::*> Columns;
     
    	static Columns m_columns;
     
    protected:
        Table() { }
     
    public:
    	virtual bool load()
    	{
    		return true;
    	}
    };
     
    class Cost : public Table<Cost>
    {
    public:
    	integer* m_val;
     
    	Cost() { }
    };
     
    template<>
    Table<Cost>::Columns Table<Cost>::m_columns = map_list_of("name", &Cost::m_val);
     
    int main(int argc, char **argv)
    {
    	cout << "test" << endl;
     
    	Cost cost;
    	return 0;
    }
    Ne compile pas nom plus à cause d'un pb de const :
    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
    g++ -c  "C:/_Perso/projets/test/table/main.cpp" -g  -o ./Debug/main.o "-IC:/_Perso/projets/lib/boost_1_41_0" "-I." 
    In file included from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/stl_algobase.h:66,
                     from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/char_traits.h:41,
                     from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/ios:41,
                     from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/ostream:40,
                     from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/iostream:40,
                     from C:/_Perso/projets/test/table/main.cpp:1:
    c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const char*, _U2 = integer* Cost::*, _T1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = ValueBase* Cost::*]':
    c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/stl_tree.h:1324:   instantiated from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_II, _II) [with _InputIterator = std::_Deque_iterator<std::pair<const char*, integer* Cost::*>, std::pair<const char*, integer* Cost::*>&, std::pair<const char*, integer* Cost::*>*>, _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*>, _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> >]'
    c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/stl_map.h:214:   instantiated from 'std::map<_Key, _Tp, _Compare, _Alloc>::map(_InputIterator, _InputIterator) [with _InputIterator = std::_Deque_iterator<std::pair<const char*, integer* Cost::*>, std::pair<const char*, integer* Cost::*>&, std::pair<const char*, integer* Cost::*>*>, _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp = ValueBase* Cost::*, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> >]'
    C:/_Perso/projets/lib/boost_1_41_0/boost/assign/list_of.hpp:163:   instantiated from 'Container boost::assign_detail::converter<DerivedTAssign, Iterator>::convert(const Container*, boost::assign_detail::default_type_tag) const [with Container = std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> > >, DerivedTAssign = boost::assign_detail::generic_list<std::pair<const char*, integer* Cost::*> >, Iterator = std::_Deque_iterator<std::pair<const char*, integer* Cost::*>, std::pair<const char*, integer* Cost::*>&, std::pair<const char*, integer* Cost::*>*>]'
    C:/_Perso/projets/lib/boost_1_41_0/boost/assign/list_of.hpp:142:   instantiated from 'Container boost::assign_detail::converter<DerivedTAssign, Iterator>::convert_to_container() const [with Container = std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> > >, DerivedTAssign = boost::assign_detail::generic_list<std::pair<const char*, integer* Cost::*> >, Iterator = std::_Deque_iterator<std::pair<const char*, integer* Cost::*>, std::pair<const char*, integer* Cost::*>&, std::pair<const char*, integer* Cost::*>*>]'
    C:/_Perso/projets/lib/boost_1_41_0/boost/assign/list_of.hpp:436:   instantiated from 'boost::assign_detail::generic_list<T>::operator Container() const [with Container = std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ValueBase* Cost::*> > >, T = std::pair<const char*, integer* Cost::*>]'
    C:/_Perso/projets/test/table/main.cpp:134:   instantiated from here
    c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/stl_pair.h:101: erreur: cannot convert 'integer* Cost::* const' to 'ValueBase* Cost::*' in initialization
    mingw32-make.exe[1]: *** [Debug/main.o] Error 1
    a cause du map_list_of qui prend un const T& en parametre...
    Jérémie

  10. #10
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    J'ai avancé un peu :

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    #include <iostream>
    #include <string>
    #include <map>
    //#include <boost/assign/list_of.hpp>
     
    using namespace std;
    //using namespace boost::assign;
     
    struct NoCheckValidator
    {
    	template <typename T>
    	static bool Check(const T& /*value*/)
    	{
    		return true;
    	}
    };
     
    class ValueBase
    {
    public:
    	virtual bool load(const string& colName) = 0;
    };
     
    template <typename T, typename C, typename V = NoCheckValidator>
    class Value
    {
    public:
    	typedef T value_t;
    	typedef C convert_functor;
    	typedef V validator_t;
     
    private:
    	value_t   m_value;
     
    public:
    	Value(const value_t& v = value_t())
    	: m_value(v)
    	{
    	}
     
    	Value(const string& colName)
    	{
    		load(colName);
    	}
     
    	virtual ~Value()
    	{
    	}
     
    	const value_t& operator()() const 
    	{
    		return get();
    	}
     
    	bool operator()(const value_t& v) 
    	{
    		return set(v);
    	}
     
    	virtual bool load(const string& colName)
    	{
    		return set( convert_functor::load(colName) );
    	}
     
    protected:
    	const value_t& get() const 
    	{
    		return m_value;
    	}
     
    	bool set(const value_t& v)
    	{
    		if (validator_t::Check(v) == false) {
    			return false;
    		}
    		m_value = v;
    		return true;
    	}
    };
     
    struct int_converter
    {
    	static int load(const string& colName)
    	{
    		cout << "int_converter::load(" << colName << ")" << endl;
    		return 1;
    	}
    };
     
    typedef Value<int, int_converter> integer;
     
    class Object
    {
    protected:
        Object() { }
    	virtual ~Object() { }
     
    public:
    	virtual bool load() = 0;
    };
     
    template <class T>
    class Table : public Object
    {
    	struct Column
    	{
    		pair<string, ValueBase* T::*> info;
     
    		Column(const string& s, ValueBase* T::* m)
    		: info(s, m) {}
     
    		const string& name() const { return info.first; }
    		ValueBase* T::* var() const { return info.second; }
    	};
     
    	static Column m_columns[];
     
    protected:
        Table() { }
     
    public:
    	virtual bool load()
    	{
    		for (size_t i = 0; i < sizeof(m_columns) / sizeof(*m_columns); ++i) {
    			ValueBase* T::* pVar = m_columns[i].var();
    			(this->*(pVar))->load(m_columns[i].name());
    		}
    		return true;
    	}
    };
     
    class Cost : public Table<Cost>
    {
    public:
    	integer* m_val;
     
    	Cost() { }
    };
     
    template<>
    Table<Cost>::Column Table<Cost>::m_columns[] = {
    	Table<Cost>::Column(string("name"), (ValueBase* Cost::*) &Cost::m_val)
    };
     
    int main(int argc, char **argv)
    {
    	cout << "test" << endl;
     
    	Cost cost;
    	return 0;
    }
    Ca ne compile toujours pas, mais je ne dois pas être loin... Un p'tit coup de main serai la bienvenue.
    Jérémie

  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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par jfouche Voir le message
    Merci pour les explications. Pour répondre à la questions sur les méthodes virtuelles, je me rends compte que je ne saurais dire... Peut être la table des méthodes virtuelles (vtable) ?
    Qu'est-ce qu'un pointeur de fonction virtuelle ?

    Citation Envoyé par jfouche Voir le message
    on peut caster sans pb un Derived* en Base*
    J'ai été tenté de faire comme ça mais je n'ai pas vraiment pris le temps de voir ce que cela peut signifier et quels peuvent être les problèmes. Une erreur de compil n'est jamais anodine...

    Citation Envoyé par jfouche Voir le message
    J'ai avancé un peu :
    [...]
    Ca ne compile toujours pas, mais je ne dois pas être loin... Un p'tit coup de main serai la bienvenue.
    Tu n'aurais pas simplement oublié de dériver value de value_base ?

Discussions similaires

  1. [POO] Pointeur sur fonction membre et héritage
    Par MrDuChnok dans le forum C++
    Réponses: 9
    Dernier message: 20/07/2006, 17h19
  2. Réponses: 5
    Dernier message: 12/06/2006, 14h56
  3. Pointeur sur fonction membre avec parametre
    Par Glosialabolas dans le forum C++
    Réponses: 7
    Dernier message: 06/02/2006, 02h32
  4. Réponses: 10
    Dernier message: 03/02/2005, 13h09
  5. Réponses: 5
    Dernier message: 12/01/2005, 20h58

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