et dedans j'ai une méthode display qui fournit des renseignements sur le
contenu de modele (je simplifie pour aller à l'essentiel)
Ma question : y-a-t-il un moyen de savoir si l'opérateur de conversion
(std::string) est défini pour les objets de la classe T ?
Actuellement, la conversion est tentée à la compilation et modele<T> n'est
pas compilé si cette conversion n'est pas possible.
Je voudrais que la conversion soit testée à l'exécution...
Est-ce que c'est possible ?
J'espère avoir été clair ...
j'ai mis en place ta solution avec une fonction template
template<class T> bool EstConvertibleEnString() { T t; return sizeof(t)==sizeof(EstConvertible); } nota : je ne peux pas écrire sizeof(T()), mon compilo n'apprécie pas (pb habituel de passage par référence non constante je suppose)
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais sizeof(makeT()), ou makeT est declaree comme retournant un T, sans definition puisque inutile. Ca evite d'avoir a instancier un objet de type T pour le code du predicat. Mais ca n'est pas suffisant, mon g++-4.1 proteste si T est un char[5] par exemple, par ce qu'il refuse la declaration d'une fonction qui retourne un tableau. Avec un T*, ca passe.
Le code precedent devient:
typedef char EstConvertible; class PasConvertible { char dummy[2]; };
template <class T> struct EstConvertibleEnString { static EstConvertible Test (std::string); static PasConvertible Test (...); static T* makeT();
enum { value = (sizeof( Test(*makeT())) == sizeof(EstConvertible)) };
bool operator()() const { return value; } };
mais il me reste un (gros) problème Qd j'écris : if (!EstConvertibleEnString<T>()) flux<<"pas convertible"<<"n"; else flux<<std::string(t)<<"n"; mon compilateur refuse de compiler la dernière ligne si l'objet n'est pas convertible :-), ce qui est en fait assez normal... En fait, ça marche bien si l'objet est convertible
On peut faire des choses compliquees avec de la specialisation de classes ou fonctions templates:
Mais bon, c'est surement pas la peine de sortir ce genre d'artillerie lourde dans le cas de l'exemple que tu as propose. Si tu veux voir une utilisation de ce genre de technique, regarde Boost.Graph, c'en est plein.
j'ai mis en place ta solution avec une fonction template
template<class T>
bool EstConvertibleEnString()
{
T t;
return sizeof(t)==sizeof(EstConvertible);
}
nota : je ne peux pas écrire sizeof(T()), mon compilo n'apprécie pas (pb
habituel de passage par référence non constante je suppose)
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais
sizeof(makeT()), ou makeT est declaree comme retournant un T,
sans definition puisque inutile. Ca evite d'avoir a instancier
un objet de type T pour le code du predicat.
Mais ca n'est pas suffisant, mon g++-4.1 proteste si T est
un char[5] par exemple, par ce qu'il refuse la declaration d'une
fonction qui retourne un tableau. Avec un T*, ca passe.
Le code precedent devient:
typedef char EstConvertible;
class PasConvertible { char dummy[2]; };
template <class T> struct EstConvertibleEnString
{
static EstConvertible Test (std::string);
static PasConvertible Test (...);
static T* makeT();
enum { value = (sizeof( Test(*makeT())) == sizeof(EstConvertible)) };
bool operator()() const { return value; }
};
mais il me reste un (gros) problème
Qd j'écris :
if (!EstConvertibleEnString<T>())
flux<<"pas convertible"<<"n";
else
flux<<std::string(t)<<"n";
mon compilateur refuse de compiler la dernière ligne si l'objet n'est pas
convertible :-), ce qui est en fait assez normal...
En fait, ça marche bien si l'objet est convertible
On peut faire des choses compliquees avec de la specialisation
de classes ou fonctions templates:
Mais bon, c'est surement pas la peine de sortir ce genre d'artillerie
lourde dans le cas de l'exemple que tu as propose. Si tu veux voir une
utilisation de ce genre de technique, regarde Boost.Graph, c'en est plein.
j'ai mis en place ta solution avec une fonction template
template<class T> bool EstConvertibleEnString() { T t; return sizeof(t)==sizeof(EstConvertible); } nota : je ne peux pas écrire sizeof(T()), mon compilo n'apprécie pas (pb habituel de passage par référence non constante je suppose)
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais sizeof(makeT()), ou makeT est declaree comme retournant un T, sans definition puisque inutile. Ca evite d'avoir a instancier un objet de type T pour le code du predicat. Mais ca n'est pas suffisant, mon g++-4.1 proteste si T est un char[5] par exemple, par ce qu'il refuse la declaration d'une fonction qui retourne un tableau. Avec un T*, ca passe.
Le code precedent devient:
typedef char EstConvertible; class PasConvertible { char dummy[2]; };
template <class T> struct EstConvertibleEnString { static EstConvertible Test (std::string); static PasConvertible Test (...); static T* makeT();
enum { value = (sizeof( Test(*makeT())) == sizeof(EstConvertible)) };
bool operator()() const { return value; } };
mais il me reste un (gros) problème Qd j'écris : if (!EstConvertibleEnString<T>()) flux<<"pas convertible"<<"n"; else flux<<std::string(t)<<"n"; mon compilateur refuse de compiler la dernière ligne si l'objet n'est pas convertible :-), ce qui est en fait assez normal... En fait, ça marche bien si l'objet est convertible
On peut faire des choses compliquees avec de la specialisation de classes ou fonctions templates:
Mais bon, c'est surement pas la peine de sortir ce genre d'artillerie lourde dans le cas de l'exemple que tu as propose. Si tu veux voir une utilisation de ce genre de technique, regarde Boost.Graph, c'en est plein.
Sylvain Togni
Marc G wrote:
quand j'écris std::string to_string(std::string const& s) {return s;} la référence pose problème avec mon compilo (BCB6) si je fais par exemple std::ostringstream flux; flux<<to_string(un_objet)<<"n"; en fait ça plante :-) je pense que c'est dû au fait qu'il y a d'abord une conversion de l'objet en une string qui est détruite qd on appelle to_string (donc il faut impérativement passer une copie) Qu'en penses-tu ?
Passer un temporaire par référence constante ne devrait pas poser de problème.
Je ne connaît pas BCB6 mais ça m'étonnerai qu'il ait ce genre de bug, cela le rendrait à peu prêt inutilisable ; le plantage doit venir d'ailleurs.
-- Sylvain Togni
Marc G wrote:
quand j'écris
std::string to_string(std::string const& s) {return s;}
la référence pose problème avec mon compilo (BCB6)
si je fais par exemple
std::ostringstream flux;
flux<<to_string(un_objet)<<"n";
en fait ça plante :-)
je pense que c'est dû au fait qu'il y a d'abord une conversion de l'objet en
une string qui est détruite qd on appelle to_string (donc il faut
impérativement passer une copie)
Qu'en penses-tu ?
Passer un temporaire par référence constante ne devrait pas
poser de problème.
Je ne connaît pas BCB6 mais ça m'étonnerai qu'il ait ce genre
de bug, cela le rendrait à peu prêt inutilisable ; le plantage
doit venir d'ailleurs.
quand j'écris std::string to_string(std::string const& s) {return s;} la référence pose problème avec mon compilo (BCB6) si je fais par exemple std::ostringstream flux; flux<<to_string(un_objet)<<"n"; en fait ça plante :-) je pense que c'est dû au fait qu'il y a d'abord une conversion de l'objet en une string qui est détruite qd on appelle to_string (donc il faut impérativement passer une copie) Qu'en penses-tu ?
Passer un temporaire par référence constante ne devrait pas poser de problème.
Je ne connaît pas BCB6 mais ça m'étonnerai qu'il ait ce genre de bug, cela le rendrait à peu prêt inutilisable ; le plantage doit venir d'ailleurs.
-- Sylvain Togni
Fabien LE LEZ
On Fri, 13 Oct 2006 08:48:03 +0200, "Marc G" :
1) pourquoi operator()() et pas operator() simplement ?
C'est une fonction, dont le nom est "operator()". void f(); operator()();
2) Pas convertible Test(...); //<- je croyais qu'il fallait au moins définir un paramètre dans les fonctions avec une liste de paramètres variable...
Pas à ma connaissance. Note qu'appeler cette fonction serait vraisemblablement un comportement indéfini. Mais on ne l'appelle pas (on ne la définit même pas).
On Fri, 13 Oct 2006 08:48:03 +0200, "Marc G" <mgueguen@metrica.fr>:
1) pourquoi operator()() et pas operator() simplement ?
C'est une fonction, dont le nom est "operator()".
void f();
operator()();
2) Pas convertible Test(...); //<- je croyais qu'il fallait au moins
définir un paramètre dans les fonctions avec une liste de paramètres
variable...
Pas à ma connaissance.
Note qu'appeler cette fonction serait vraisemblablement un
comportement indéfini. Mais on ne l'appelle pas (on ne la définit même
pas).
1) pourquoi operator()() et pas operator() simplement ?
C'est une fonction, dont le nom est "operator()". void f(); operator()();
2) Pas convertible Test(...); //<- je croyais qu'il fallait au moins définir un paramètre dans les fonctions avec une liste de paramètres variable...
Pas à ma connaissance. Note qu'appeler cette fonction serait vraisemblablement un comportement indéfini. Mais on ne l'appelle pas (on ne la définit même pas).
Fabien LE LEZ
On Fri, 13 Oct 2006 10:45:09 +0200, "Marc G" :
bool EstConvertibleEnString() { T t; return sizeof(t)==sizeof(EstConvertible);
Gniii ? D'où sors-tu cette idée ? Je ne vois vraiment pas pourquoi ça pourrait marcher, ni même ce que c'est censé faire.
On Fri, 13 Oct 2006 10:45:09 +0200, "Marc G" <mgueguen@metrica.fr>:
bool EstConvertibleEnString()
{
T t;
return sizeof(t)==sizeof(EstConvertible);
Gniii ? D'où sors-tu cette idée ?
Je ne vois vraiment pas pourquoi ça pourrait marcher, ni même ce que
c'est censé faire.
On Fri, 13 Oct 2006 12:30:41 +0200, Michel Decima :
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais sizeof(makeT()), ou makeT est declaree comme retournant un T,
Non. Dans mon message, les fonctions renvoient des types fixes : soit un "EstConvertible" (sizeof==1), soit un "PasConvertible" (sizeof>=2).
Michel Decima
Fabien LE LEZ wrote:
On Fri, 13 Oct 2006 12:30:41 +0200, Michel Decima :
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais sizeof(makeT()), ou makeT est declaree comme retournant un T,
Non. Dans mon message, les fonctions renvoient des types fixes : soit un "EstConvertible" (sizeof==1), soit un "PasConvertible" (sizeof>=2).
Mon clavier a fourché, donc je corrige:
Dans ton code, il y a sizeof(Test(T())), et dans celui de Alexandrescu il y a sizeof(Test(makeT())), avec makeT() qui retourne un T.
La version qui utilise un constructeur pose des problemes divers (en particulier quand il n'y a pas ce ctor par defaut), et me donnait un mauvais resultat pour le calcul de value (dans mon code). La version avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un tableau ("toto" => char[5]). Avec une fonction qui retourne un pointeur telle que "T* makePtrT()" le probleme ne se pose plus (mais il y en a surement d'autre...)
Fabien LE LEZ wrote:
On Fri, 13 Oct 2006 12:30:41 +0200, Michel Decima
<michel.decima@orange-ft.com>:
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais
sizeof(makeT()), ou makeT est declaree comme retournant un T,
Non. Dans mon message, les fonctions renvoient des types fixes : soit
un "EstConvertible" (sizeof==1), soit un "PasConvertible" (sizeof>=2).
Mon clavier a fourché, donc je corrige:
Dans ton code, il y a sizeof(Test(T())), et dans celui de Alexandrescu
il y a sizeof(Test(makeT())), avec makeT() qui retourne un T.
La version qui utilise un constructeur pose des problemes divers (en
particulier quand il n'y a pas ce ctor par defaut), et me donnait un
mauvais resultat pour le calcul de value (dans mon code). La version
avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un
tableau ("toto" => char[5]). Avec une fonction qui retourne un pointeur
telle que "T* makePtrT()" le probleme ne se pose plus (mais il y en a
surement d'autre...)
On Fri, 13 Oct 2006 12:30:41 +0200, Michel Decima :
Dans le texte cite par Fabien, il n'y a pas sizeof(T()) mais sizeof(makeT()), ou makeT est declaree comme retournant un T,
Non. Dans mon message, les fonctions renvoient des types fixes : soit un "EstConvertible" (sizeof==1), soit un "PasConvertible" (sizeof>=2).
Mon clavier a fourché, donc je corrige:
Dans ton code, il y a sizeof(Test(T())), et dans celui de Alexandrescu il y a sizeof(Test(makeT())), avec makeT() qui retourne un T.
La version qui utilise un constructeur pose des problemes divers (en particulier quand il n'y a pas ce ctor par defaut), et me donnait un mauvais resultat pour le calcul de value (dans mon code). La version avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un tableau ("toto" => char[5]). Avec une fonction qui retourne un pointeur telle que "T* makePtrT()" le probleme ne se pose plus (mais il y en a surement d'autre...)
Fabien LE LEZ
On Fri, 13 Oct 2006 20:02:05 +0200, Michel Decima :
La version avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un tableau ("toto" => char[5]).
Est-ce qu'un "char[5]" peut être un paramètre template ?
On Fri, 13 Oct 2006 20:02:05 +0200, Michel Decima
<michel.decima@wanadoo.fr>:
La version
avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un
tableau ("toto" => char[5]).
Est-ce qu'un "char[5]" peut être un paramètre template ?
Si je dé-commente le deuxieme appel a print(), g++ me donne le message d'erreur suivant:
invalid initialization of reference of type 'const char (&)[5]' from expression of type 'const char[7]' in passing argument 1 of `void print(const T&) [with T = char[5]]'
Est-ce qu'un "char[5]" peut être un paramètre template ?
Si je dé-commente le deuxieme appel a print(), g++ me donne le
message d'erreur suivant:
invalid initialization of reference of type 'const char (&)[5]'
from expression of type 'const char[7]' in passing argument 1 of
`void print(const T&) [with T = char[5]]'
Si je dé-commente le deuxieme appel a print(), g++ me donne le message d'erreur suivant:
invalid initialization of reference of type 'const char (&)[5]' from expression of type 'const char[7]' in passing argument 1 of `void print(const T&) [with T = char[5]]'
Gabriel Dos Reis
Fabien LE LEZ writes:
| On Fri, 13 Oct 2006 20:02:05 +0200, Michel Decima | : | | > La version | >avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un | >tableau ("toto" => char[5]). | | Est-ce qu'un "char[5]" peut être un paramètre template ?
La question est plutôt « est-ce qu'un tableau peut être type de retour d'une fonction ? » La réponse est « non » ; étrangement. Donc on ne peut pas instantier makeT() avec un T = char[5].
Fabien LE LEZ <gramster@gramster.com> writes:
| On Fri, 13 Oct 2006 20:02:05 +0200, Michel Decima
| <michel.decima@wanadoo.fr>:
|
| > La version
| >avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un
| >tableau ("toto" => char[5]).
|
| Est-ce qu'un "char[5]" peut être un paramètre template ?
La question est plutôt « est-ce qu'un tableau peut être type de retour
d'une fonction ? » La réponse est « non » ; étrangement.
Donc on ne peut pas instantier makeT() avec un T = char[5].
| On Fri, 13 Oct 2006 20:02:05 +0200, Michel Decima | : | | > La version | >avec "T makeT()" est meilleure, mais g++-4 la refuse si T est un | >tableau ("toto" => char[5]). | | Est-ce qu'un "char[5]" peut être un paramètre template ?
La question est plutôt « est-ce qu'un tableau peut être type de retour d'une fonction ? » La réponse est « non » ; étrangement. Donc on ne peut pas instantier makeT() avec un T = char[5].
Fabien LE LEZ
On 14 Oct 2006 02:23:07 +0200, Gabriel Dos Reis :
La question est plutôt « est-ce qu'un tableau peut être type de retour d'une fonction ? » La réponse est « non » ; étrangement.
Ça, je savais.
template<class T> modele
Ma question : y-a-t-il un moyen de savoir si l'opérateur de conversion (std::string) est défini pour les objets de la classe T ?
Je me demandais donc s'il envisageait le cas où T == char[5].
On 14 Oct 2006 02:23:07 +0200, Gabriel Dos Reis
<gdr@integrable-solutions.net>:
La question est plutôt « est-ce qu'un tableau peut être type de retour
d'une fonction ? » La réponse est « non » ; étrangement.
Ça, je savais.
template<class T>
modele
Ma question : y-a-t-il un moyen de savoir si l'opérateur de conversion
(std::string) est défini pour les objets de la classe T ?
Je me demandais donc s'il envisageait le cas où T == char[5].