OVH Cloud OVH Cloud

pb de conversion en std::string

23 réponses
Avatar
MGN
mon problème est simple.
J'ai un modèle de classe

template<class T>
modele
{
// blablabla...

std::string display(void) const;
};

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 ...

10 réponses

1 2 3
Avatar
Michel Decima
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:

struct True {}; struct False {};
template <int B> struct Boolean { typedef True type; };
template<> struct Boolean<0> { typedef False type; } ;

template <typename T>
void print(T const& value, True const& tag)
{
std::cout << "convertible: " << std::string(value) << std::endl;
}

template <typename T>
void print(T const& value, False const& tag)
{
std::cout << "pas convertible" << std::endl;
}

template <typename T>
void print(T const& value)
{
typedef typename
Boolean< IsConvertibleToString<T>::value >::type TagType;
print(value, TagType());
}

int main() {
print("toto");
print(12);
}

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.

Avatar
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

Avatar
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).

Avatar
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.

Avatar
Fabien LE LEZ
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).

Avatar
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...)


Avatar
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 ?

Avatar
Michel Decima

Est-ce qu'un "char[5]" peut être un paramètre template ?


Je dirais que oui:

template <typename T>
void print(T const& x) {
std::cout << x << std::endl;
}

int main() {
print< char[5] >("cinq");
// print< char[5] >("cinq+2");
return 0;
}

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]]'

Avatar
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].
Avatar
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].

1 2 3