Michaël Monerau" <cort@meloo.com> a écrit dans le message de
news:pGXdb.181652$hd6.2309645@news.chello.at...
> Christophe Lephay wrote:
> >> template <class T>
> >> class UVar
> >> {
> >> public:
> >> typedef const_ref_type const T&;
> >>
> >> virtual xxx GetValue () const = 0;
> >> // je voudrais :
> >> virtual const T& GetValue () const = 0;
> >> };
> >
> > J'ai un jour été confronté à ce problème, et je l'ai résolu en
> > passant par un stream pour extraire la valeur...
>
> C'est-à-dire ? Je ne vois pas ce que tu veux dire... Mon but est aussi de
> passer par un stream ensuite pour l'afficher. Le type 'T' doit alors aussi
> surcharger l'opérateur '<<' pour lui...
>
> Mais si tu fais passer directement par un stream, comment récupérer
> l'information si tu ne sais pas de quel type elle est ?
La méthode classique...
class base
{
protected:
virtual void print( ostream& ostr ) = 0;
};
"Michaël Monerau" a écrit dans le message de news:9wgeb.200005$
Christophe Lephay wrote:
Que veux-tu dire par "récupérer la valeur" ?
En relisant de plus près les posts (et en essayant d'imaginer le code), je me suis rendu compte que j'avais mal compris ta solution.
Elle ne correspond pas à ce que je veux, puisqu'on revient avec un pointeur
base*. Or, moi, je voudrais la *valeur* qui est réellement contenue par la base. Mais c'est en fait impossible je pense, sauf en passant par ma méthode
de cast sauvage et unsafe...
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de connaitre le type de cette valeur au moment où tu veux la récupérer. Partant de là, tu as deux options : soit tu as des fonctions dont la signature va différer selon le type de la valeur contenue (et rendre la fonction virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu as la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il n'y a pas d'alternative (du moins pas que je sache). Au moins, le fait de passer par un flux permet d'avoir une interface commune...
// on est obligé de connaitre le type pour récupérer la valeur int value; str >> value;
str << 20; str >> iderived;
Avec un cast, le problème est le même :
derived< int > iderived( 10 );
int i = static_cast< int >( iderived.getValue() );
// ou alors base * pbase = &iderived; i = static_cast< int >( pbase->getValue() );
Au passage, je ne suis pas certain que le static_cast fonctionne (en fait, je suis plutôt certain du contraire), mais j'ai la flemme de tenter avec des dynamic ou reinterpret_cast. Dans tous les cas, cast ou flux, tu es obligé de connaitre le type de l'info à récupérer. Je trouve l'utilisation d'un flux bien plus propre...
Chris
"Michaël Monerau" <cort@meloo.com> a écrit dans le message de
news:9wgeb.200005$hd6.2577904@news.chello.at...
Christophe Lephay wrote:
Que veux-tu dire par "récupérer la valeur" ?
En relisant de plus près les posts (et en essayant d'imaginer le code), je
me suis rendu compte que j'avais mal compris ta solution.
Elle ne correspond pas à ce que je veux, puisqu'on revient avec un
pointeur
base*. Or, moi, je voudrais la *valeur* qui est réellement contenue par la
base. Mais c'est en fait impossible je pense, sauf en passant par ma
méthode
de cast sauvage et unsafe...
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de
connaitre le type de cette valeur au moment où tu veux la récupérer. Partant
de là, tu as deux options : soit tu as des fonctions dont la signature va
différer selon le type de la valeur contenue (et rendre la fonction
virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu as
la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de
connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il n'y
a pas d'alternative (du moins pas que je sache). Au moins, le fait de passer
par un flux permet d'avoir une interface commune...
// on est obligé de connaitre le type pour récupérer la valeur
int value;
str >> value;
str << 20;
str >> iderived;
Avec un cast, le problème est le même :
derived< int > iderived( 10 );
int i = static_cast< int >( iderived.getValue() );
// ou alors
base * pbase = &iderived;
i = static_cast< int >( pbase->getValue() );
Au passage, je ne suis pas certain que le static_cast fonctionne (en fait,
je suis plutôt certain du contraire), mais j'ai la flemme de tenter avec des
dynamic ou reinterpret_cast.
Dans tous les cas, cast ou flux, tu es obligé de connaitre le type de l'info
à récupérer. Je trouve l'utilisation d'un flux bien plus propre...
"Michaël Monerau" a écrit dans le message de news:9wgeb.200005$
Christophe Lephay wrote:
Que veux-tu dire par "récupérer la valeur" ?
En relisant de plus près les posts (et en essayant d'imaginer le code), je me suis rendu compte que j'avais mal compris ta solution.
Elle ne correspond pas à ce que je veux, puisqu'on revient avec un pointeur
base*. Or, moi, je voudrais la *valeur* qui est réellement contenue par la base. Mais c'est en fait impossible je pense, sauf en passant par ma méthode
de cast sauvage et unsafe...
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de connaitre le type de cette valeur au moment où tu veux la récupérer. Partant de là, tu as deux options : soit tu as des fonctions dont la signature va différer selon le type de la valeur contenue (et rendre la fonction virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu as la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il n'y a pas d'alternative (du moins pas que je sache). Au moins, le fait de passer par un flux permet d'avoir une interface commune...
// on est obligé de connaitre le type pour récupérer la valeur int value; str >> value;
str << 20; str >> iderived;
Avec un cast, le problème est le même :
derived< int > iderived( 10 );
int i = static_cast< int >( iderived.getValue() );
// ou alors base * pbase = &iderived; i = static_cast< int >( pbase->getValue() );
Au passage, je ne suis pas certain que le static_cast fonctionne (en fait, je suis plutôt certain du contraire), mais j'ai la flemme de tenter avec des dynamic ou reinterpret_cast. Dans tous les cas, cast ou flux, tu es obligé de connaitre le type de l'info à récupérer. Je trouve l'utilisation d'un flux bien plus propre...
Chris
Christophe Lephay
"Christophe Lephay" a écrit dans le message de news:blc6a5$8ic$
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de connaitre le type de cette valeur au moment où tu veux la récupérer. Partant
de là, tu as deux options : soit tu as des fonctions dont la signature va différer selon le type de la valeur contenue (et rendre la fonction virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu as
la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il n'y
a pas d'alternative (du moins pas que je sache). Au moins, le fait de passer
par un flux permet d'avoir une interface commune...
Oups rectificatif : l'alternative dont tu parles (et auquel mon exemple s'adressait, du reste) à base de cast sauvage permet bien d'avoir la même signature...
Chris
"Christophe Lephay" <christophe-lephay@wanadoo.fr> a écrit dans le message
de news:blc6a5$8ic$1@news-reader3.wanadoo.fr...
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de
connaitre le type de cette valeur au moment où tu veux la récupérer.
Partant
de là, tu as deux options : soit tu as des fonctions dont la signature va
différer selon le type de la valeur contenue (et rendre la fonction
virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu
as
la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de
connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il
n'y
a pas d'alternative (du moins pas que je sache). Au moins, le fait de
passer
par un flux permet d'avoir une interface commune...
Oups rectificatif : l'alternative dont tu parles (et auquel mon exemple
s'adressait, du reste) à base de cast sauvage permet bien d'avoir la même
signature...
"Christophe Lephay" a écrit dans le message de news:blc6a5$8ic$
Su tu veux la valeur contenue par l'objet, tu es de toute façon obligé de connaitre le type de cette valeur au moment où tu veux la récupérer. Partant
de là, tu as deux options : soit tu as des fonctions dont la signature va différer selon le type de la valeur contenue (et rendre la fonction virtuelle n'est donc d'aucune utilité), soit tu passes via un flux et tu as
la même signature.
C'est le problème qu'on trouve dans la sérialisation. Tu es obligé de connaitre le type de la donnée à récupérer avant de pouvoir le faire. Il n'y
a pas d'alternative (du moins pas que je sache). Au moins, le fait de passer
par un flux permet d'avoir une interface commune...
Oups rectificatif : l'alternative dont tu parles (et auquel mon exemple s'adressait, du reste) à base de cast sauvage permet bien d'avoir la même signature...
Chris
Loïc Joly
Michaël Monerau wrote:
Loïc Joly wrote:
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend pas du type, et que tout ton code est templaté sur le type, la question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour de get() ?
La classe de base n'a pas de fonction get, seules les classes dérivées en ont une.
-- Loïc
Michaël Monerau wrote:
Loïc Joly wrote:
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend
pas du type, et que tout ton code est templaté sur le type, la
question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour
de get() ?
La classe de base n'a pas de fonction get, seules les classes dérivées
en ont une.
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend pas du type, et que tout ton code est templaté sur le type, la question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour de get() ?
La classe de base n'a pas de fonction get, seules les classes dérivées en ont une.
-- Loïc
tib.motuelle
"Michaël Monerau" wrote in message news:<azgeb.200020$...
Loïc Joly wrote:
Michaël Monerau wrote:
Christophe Lephay wrote:
La méthode classique...
class base;
template< class T > class derived : public base
Ok, mais là c'est seulement pour le mettre dans un string. Admettons que maintenant, je veuille récupérer la valeur contenue dans derived, avec un pointeur vers base... Est-ce possible en C++ ?
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend pas du type, et que tout ton code est templaté sur le type, la question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour de get() ? Un void* que je recaste dans le bon type (ce que je fais dans ma fonction). Mais après, comment déterminer le bon type depuis seulement un pointeur vers base* ? Pour l'instant, je n'ai pas trouvé et je fais confiance à l'utilisateur, ce qui peut vite devenir la merde, sauf si j'ai des typedef's pour tous les noms d'options...
Si maintenant tu veux à un moment faire une opération spécifique au type (par exemple, si tu veux diviser deux derived<double> mais pas deux derived<string>), il va falloir déterminer ce qu'est vraiment ton type.
Tu dois pouvoir faire ça soit par downcast explicite (dynamic_cast), soit par détermination du type par surcharge de fonction (tu as un f(string), un f(double)... et tu appèles f(T)).
Oui, mais ça restreint... Je voudrais vraiment que cette classe puisse prendre n'importe quelle type comme valeur. (voir réponse à James que je vais écrire :p).
Le dynamic me semble adapté dans ton cas. Ajoute a la classe de base une fonction template qui réalise le dynamic_cast et vérifie sa validité, et AMHA tu obtiens ce que tu recherches. En gros:
template<class T> class derived;
class base { public: template<class T> const T& value() const { const derived<T>* d = dynamic_cast<const derived<T>*>(this); if (d == 0) throw "Invalid type"; return d->value(); }
protected: virtual ~base() {} };
template<class T> class derived : public base { public: derived(const T& value) : value_(value) {} const T& value() const { return value_; }
private: T value_; };
int main() { std::map<std::string, boost::shared_ptr<base> > atts; atts["age"] = new derived<int>(16); atts["prenom"] = new derived<std::string>("Michael");
Comme te l'a dit James, tu peux également utiliser boost::any pour faire ce genre de choses.
Bertrand
"Michaël Monerau" <cort@meloo.com> wrote in message news:<azgeb.200020$hd6.2576530@news.chello.at>...
Loïc Joly wrote:
Michaël Monerau wrote:
Christophe Lephay wrote:
La méthode classique...
class base;
template< class T >
class derived : public base
Ok, mais là c'est seulement pour le mettre dans un string. Admettons
que maintenant, je veuille récupérer la valeur contenue dans
derived, avec un pointeur vers base... Est-ce possible en C++ ?
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend
pas du type, et que tout ton code est templaté sur le type, la
question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour
de get() ? Un void* que je recaste dans le bon type (ce que je fais dans ma
fonction). Mais après, comment déterminer le bon type depuis seulement un
pointeur vers base* ? Pour l'instant, je n'ai pas trouvé et je fais
confiance à l'utilisateur, ce qui peut vite devenir la merde, sauf si j'ai
des typedef's pour tous les noms d'options...
Si maintenant tu veux à un moment faire une opération spécifique au
type (par exemple, si tu veux diviser deux derived<double> mais pas
deux derived<string>), il va falloir déterminer ce qu'est vraiment
ton type.
Tu dois pouvoir faire ça soit par downcast explicite (dynamic_cast),
soit par détermination du type par surcharge de fonction (tu as un
f(string), un f(double)... et tu appèles f(T)).
Oui, mais ça restreint... Je voudrais vraiment que cette classe puisse
prendre n'importe quelle type comme valeur. (voir réponse à James que je
vais écrire :p).
Le dynamic me semble adapté dans ton cas.
Ajoute a la classe de base une fonction template qui réalise le
dynamic_cast et vérifie sa validité, et AMHA tu obtiens ce que tu
recherches.
En gros:
template<class T>
class derived;
class base
{
public:
template<class T>
const T& value() const
{
const derived<T>* d = dynamic_cast<const derived<T>*>(this);
if (d == 0) throw "Invalid type";
return d->value();
}
protected:
virtual ~base() {}
};
template<class T>
class derived : public base
{
public:
derived(const T& value) : value_(value) {}
const T& value() const { return value_; }
private:
T value_;
};
int main()
{
std::map<std::string, boost::shared_ptr<base> > atts;
atts["age"] = new derived<int>(16);
atts["prenom"] = new derived<std::string>("Michael");
"Michaël Monerau" wrote in message news:<azgeb.200020$...
Loïc Joly wrote:
Michaël Monerau wrote:
Christophe Lephay wrote:
La méthode classique...
class base;
template< class T > class derived : public base
Ok, mais là c'est seulement pour le mettre dans un string. Admettons que maintenant, je veuille récupérer la valeur contenue dans derived, avec un pointeur vers base... Est-ce possible en C++ ?
Tant que tu veux la "récupérer" d'une façon générique qui ne dépend pas du type, et que tout ton code est templaté sur le type, la question ne se pose pas vraiment.
Oui, mais la base n'est pas templatée. Du coup, comment déterminer le retour de get() ? Un void* que je recaste dans le bon type (ce que je fais dans ma fonction). Mais après, comment déterminer le bon type depuis seulement un pointeur vers base* ? Pour l'instant, je n'ai pas trouvé et je fais confiance à l'utilisateur, ce qui peut vite devenir la merde, sauf si j'ai des typedef's pour tous les noms d'options...
Si maintenant tu veux à un moment faire une opération spécifique au type (par exemple, si tu veux diviser deux derived<double> mais pas deux derived<string>), il va falloir déterminer ce qu'est vraiment ton type.
Tu dois pouvoir faire ça soit par downcast explicite (dynamic_cast), soit par détermination du type par surcharge de fonction (tu as un f(string), un f(double)... et tu appèles f(T)).
Oui, mais ça restreint... Je voudrais vraiment que cette classe puisse prendre n'importe quelle type comme valeur. (voir réponse à James que je vais écrire :p).
Le dynamic me semble adapté dans ton cas. Ajoute a la classe de base une fonction template qui réalise le dynamic_cast et vérifie sa validité, et AMHA tu obtiens ce que tu recherches. En gros:
template<class T> class derived;
class base { public: template<class T> const T& value() const { const derived<T>* d = dynamic_cast<const derived<T>*>(this); if (d == 0) throw "Invalid type"; return d->value(); }
protected: virtual ~base() {} };
template<class T> class derived : public base { public: derived(const T& value) : value_(value) {} const T& value() const { return value_; }
private: T value_; };
int main() { std::map<std::string, boost::shared_ptr<base> > atts; atts["age"] = new derived<int>(16); atts["prenom"] = new derived<std::string>("Michael");