Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper {
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Plus tard, on a changé le code, et remplace int par std::string.
Et la, c'est le drame : le compilateur refuse le test d'egalite,
comme s'il ne trouvait pas l'operateur de conversion automatique
Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper {
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Plus tard, on a changé le code, et remplace int par std::string.
Et la, c'est le drame : le compilateur refuse le test d'egalite,
comme s'il ne trouvait pas l'operateur de conversion automatique
Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper {
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Plus tard, on a changé le code, et remplace int par std::string.
Et la, c'est le drame : le compilateur refuse le test d'egalite,
comme s'il ne trouvait pas l'operateur de conversion automatique
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='
J'ai un soucis de comprehension sur une classe qui possede un
operateur de conversion automatique (j'aurais du me mefier, on
m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper
{
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Dans le code, on avait ceci :
Wrapper< int > x ;
if ( x == 0 ) {
// ...
}
Pour le test d'egalite, il y a conversion automatique vers int
puis appel de l'operateur == sur int, ca compile, ca marche,
tout va bien.
Plus tard, on a changé le code, et remplace int par
std::string. Et la, c'est le drame : le compilateur refuse le
test d'egalite, comme s'il ne trouvait pas l'operateur de
conversion automatique :
Wrapper< std::string > x ;
if ( x == std::string( "" ) ) {
// ...
}
erreur : no match for 'operator==' in 'x == y'
(testé avec gcc-4.1.2, xlC-8, Comeau 4.3.10.1).
Pour essayer de comprendre, j'ai remplacé std::string par une
classe vide, et la ca compile :
struct Empty {} ;
bool operator==( Empty const&, Empty const& ) { return true ; }
Wrapper< Empty > x ;
if ( x == Empty() ) ; // OK
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator= ='
Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
J'ai un soucis de comprehension sur une classe qui possede un
operateur de conversion automatique (j'aurais du me mefier, on
m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper
{
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Dans le code, on avait ceci :
Wrapper< int > x ;
if ( x == 0 ) {
// ...
}
Pour le test d'egalite, il y a conversion automatique vers int
puis appel de l'operateur == sur int, ca compile, ca marche,
tout va bien.
Plus tard, on a changé le code, et remplace int par
std::string. Et la, c'est le drame : le compilateur refuse le
test d'egalite, comme s'il ne trouvait pas l'operateur de
conversion automatique :
Wrapper< std::string > x ;
if ( x == std::string( "" ) ) {
// ...
}
erreur : no match for 'operator==' in 'x == y'
(testé avec gcc-4.1.2, xlC-8, Comeau 4.3.10.1).
Pour essayer de comprendre, j'ai remplacé std::string par une
classe vide, et la ca compile :
struct Empty {} ;
bool operator==( Empty const&, Empty const& ) { return true ; }
Wrapper< Empty > x ;
if ( x == Empty() ) ; // OK
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator= ='
Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
J'ai un soucis de comprehension sur une classe qui possede un
operateur de conversion automatique (j'aurais du me mefier, on
m'avais prevenu, mais je l'ai fait quand meme...)
Donc, soit la classe en question, reduite a sa plus
simple expression :
template< typename T >
class Wrapper
{
public:
explicit Wrapper( T const& value = T() ) : myValue( value ) {}
operator T () const { return myValue ; }
private:
T myValue ;
} ;
Dans le code, on avait ceci :
Wrapper< int > x ;
if ( x == 0 ) {
// ...
}
Pour le test d'egalite, il y a conversion automatique vers int
puis appel de l'operateur == sur int, ca compile, ca marche,
tout va bien.
Plus tard, on a changé le code, et remplace int par
std::string. Et la, c'est le drame : le compilateur refuse le
test d'egalite, comme s'il ne trouvait pas l'operateur de
conversion automatique :
Wrapper< std::string > x ;
if ( x == std::string( "" ) ) {
// ...
}
erreur : no match for 'operator==' in 'x == y'
(testé avec gcc-4.1.2, xlC-8, Comeau 4.3.10.1).
Pour essayer de comprendre, j'ai remplacé std::string par une
classe vide, et la ca compile :
struct Empty {} ;
bool operator==( Empty const&, Empty const& ) { return true ; }
Wrapper< Empty > x ;
if ( x == Empty() ) ; // OK
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator= ='
Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
On Wed, 27 May 2009 18:24:25 +0200, Michel Decima :
Simplifions un peu :
template < typename T > struct Generic {} ;
template < typename T >
void f (Generic< T > const&) {}
Wrapper< Generic< int > > x ;
f (x);
f<>() est une fonction template.
Le compilateur peut trouver (inférer) lui-même le type paramètre
template, à condition qu'aucune conversion implicite ne soit
nécessaire.
En revanche, tu peux indiquer le type explicitement :
Wrapper< Generic< int > > x ;
f<int> (x);
f<int>() est une fonction normale, qui accepte comme paramètre un
"Generic<int> const&", et x est convertible en ce type, donc tout va
bien.
Évidemment, avec operator== et basic_string<plein_de_trucs>,
expliciter les paramètres templates s'avère plus délicat :-(
On Wed, 27 May 2009 18:24:25 +0200, Michel Decima :
Simplifions un peu :
template < typename T > struct Generic {} ;
template < typename T >
void f (Generic< T > const&) {}
Wrapper< Generic< int > > x ;
f (x);
f<>() est une fonction template.
Le compilateur peut trouver (inférer) lui-même le type paramètre
template, à condition qu'aucune conversion implicite ne soit
nécessaire.
En revanche, tu peux indiquer le type explicitement :
Wrapper< Generic< int > > x ;
f<int> (x);
f<int>() est une fonction normale, qui accepte comme paramètre un
"Generic<int> const&", et x est convertible en ce type, donc tout va
bien.
Évidemment, avec operator== et basic_string<plein_de_trucs>,
expliciter les paramètres templates s'avère plus délicat :-(
On Wed, 27 May 2009 18:24:25 +0200, Michel Decima :
Simplifions un peu :
template < typename T > struct Generic {} ;
template < typename T >
void f (Generic< T > const&) {}
Wrapper< Generic< int > > x ;
f (x);
f<>() est une fonction template.
Le compilateur peut trouver (inférer) lui-même le type paramètre
template, à condition qu'aucune conversion implicite ne soit
nécessaire.
En revanche, tu peux indiquer le type explicitement :
Wrapper< Generic< int > > x ;
f<int> (x);
f<int>() est une fonction normale, qui accepte comme paramètre un
"Generic<int> const&", et x est convertible en ce type, donc tout va
bien.
Évidemment, avec operator== et basic_string<plein_de_trucs>,
expliciter les paramètres templates s'avère plus délicat :-(
Michel Decima a écrit :Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
mais non, c'est utile.
j'aurais mis un operator (paramétré) de test dans le template:
bool operator ==(T const& t) const {
return myValue == t;
}
ça coûte pas grand chose et corrige le pb.
Michel Decima a écrit :
Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
mais non, c'est utile.
j'aurais mis un operator (paramétré) de test dans le template:
bool operator ==(T const& t) const {
return myValue == t;
}
ça coûte pas grand chose et corrige le pb.
Michel Decima a écrit :Bonjour,
J'ai un soucis de comprehension sur une classe qui possede
un operateur de conversion automatique (j'aurais du me mefier,
on m'avais prevenu, mais je l'ai fait quand meme...)
mais non, c'est utile.
j'aurais mis un operator (paramétré) de test dans le template:
bool operator ==(T const& t) const {
return myValue == t;
}
ça coûte pas grand chose et corrige le pb.
On May 27, 6:24 pm, Michel Decima wrote:erreur : no match for 'operator==' in 'x == y'
Ce n'est pas la conversion implicite qu'il ne trouve pas. C'est
opérateur == tout court. Les seuls opérateurs == dont il peut
être question, ce sont ceux dans <string>. Sauf qu'ils ne sont
pas des fonctions, mais des templates, et ne peuvent être pris
en compte qu'une fois instantiées. Et la déduction automatique
des types, qui permettrait l'instantiation, ne prend pas en
compte les conversions implicites (ou seulement quelques
conversions très simples, du genre tableau en pointeur).
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
La différence, ce n'est pas T, c'est l'operator==. Si
l'operator== est une fonction templatée, la déduction de type,
ne prenant pas en compte les conversions implicites, échouera,
et il n'y aura pas de fonction à ajouter à l'ensemble de
surcharge.
La solution évidente, c'est de ne jamais faire operator== un
template. Faute d'autres solutions :
template< typename T >
class Generic
{
public:
friend bool operator==( Generic const& lhs, Generic const&
rhs )
{
return true /* ou d'autre chose */ ;
}
} ;
(Du coup, l'operator== n'est pas un template. Mais il y en a
autant qu'il faut.)
Pour std::string, évidement, il n'y a rien que tu puisses faire.
(Une question intéressante : est-ce qu'une implémentation de
std::basic_string a le droit de faire comme ci-dessus ?)
On May 27, 6:24 pm, Michel Decima <michel.dec...@orange-ft.com> wrote:
erreur : no match for 'operator==' in 'x == y'
Ce n'est pas la conversion implicite qu'il ne trouve pas. C'est
opérateur == tout court. Les seuls opérateurs == dont il peut
être question, ce sont ceux dans <string>. Sauf qu'ils ne sont
pas des fonctions, mais des templates, et ne peuvent être pris
en compte qu'une fois instantiées. Et la déduction automatique
des types, qui permettrait l'instantiation, ne prend pas en
compte les conversions implicites (ou seulement quelques
conversions très simples, du genre tableau en pointeur).
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :
template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }
Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='
Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
La différence, ce n'est pas T, c'est l'operator==. Si
l'operator== est une fonction templatée, la déduction de type,
ne prenant pas en compte les conversions implicites, échouera,
et il n'y aura pas de fonction à ajouter à l'ensemble de
surcharge.
La solution évidente, c'est de ne jamais faire operator== un
template. Faute d'autres solutions :
template< typename T >
class Generic
{
public:
friend bool operator==( Generic const& lhs, Generic const&
rhs )
{
return true /* ou d'autre chose */ ;
}
} ;
(Du coup, l'operator== n'est pas un template. Mais il y en a
autant qu'il faut.)
Pour std::string, évidement, il n'y a rien que tu puisses faire.
(Une question intéressante : est-ce qu'une implémentation de
std::basic_string a le droit de faire comme ci-dessus ?)
On May 27, 6:24 pm, Michel Decima wrote:erreur : no match for 'operator==' in 'x == y'
Ce n'est pas la conversion implicite qu'il ne trouve pas. C'est
opérateur == tout court. Les seuls opérateurs == dont il peut
être question, ce sont ceux dans <string>. Sauf qu'ils ne sont
pas des fonctions, mais des templates, et ne peuvent être pris
en compte qu'une fois instantiées. Et la déduction automatique
des types, qui permettrait l'instantiation, ne prend pas en
compte les conversions implicites (ou seulement quelques
conversions très simples, du genre tableau en pointeur).
Par contre, si la classe encapsulee est template, alors
ca ne compile plus :template < typename T >
struct Generic {} ;
template < typename T >
bool operator==( Generic< T > const&, Generic< T > const& )
{ return true ; }Wrapper< Generic< int > > x ;
if ( x == Generic< int>() ) ; // KO : no match for 'operator=='Donc, il semblerait que dans une expression d'egalité,
l'operateur de conversion automatique de Wrapper< T > n'est
pas trouvé lorsque T est lui-meme un type template.
La différence, ce n'est pas T, c'est l'operator==. Si
l'operator== est une fonction templatée, la déduction de type,
ne prenant pas en compte les conversions implicites, échouera,
et il n'y aura pas de fonction à ajouter à l'ensemble de
surcharge.
La solution évidente, c'est de ne jamais faire operator== un
template. Faute d'autres solutions :
template< typename T >
class Generic
{
public:
friend bool operator==( Generic const& lhs, Generic const&
rhs )
{
return true /* ou d'autre chose */ ;
}
} ;
(Du coup, l'operator== n'est pas un template. Mais il y en a
autant qu'il faut.)
Pour std::string, évidement, il n'y a rien que tu puisses faire.
(Une question intéressante : est-ce qu'une implémentation de
std::basic_string a le droit de faire comme ci-dessus ?)
James Kanze a écrit :
> La solution évidente, c'est de ne jamais faire operator== un
> template. Faute d'autres solutions :
> template< typename T >
> class Generic
> {
> public:
> friend bool operator==( Generic const& lhs, Generic const&
> rhs )
> {
> return true /* ou d'autre chose */ ;
> }
> } ;
> (Du coup, l'operator== n'est pas un template. Mais il y en a
> autant qu'il faut.)
Oui, ca marche, mais c'est quand meme subtil: on utilise le
friend non pas pour donner l'accès aux membres proteges/prives
de Generic, mais pour rendre operator== non template... Bref,
c'est pas evident a la premiere lecture.
> Pour std::string, évidement, il n'y a rien que tu puisses
> faire.
Et c'est bien mon probleme...
> (Une question intéressante : est-ce qu'une implémentation de
> std::basic_string a le droit de faire comme ci-dessus ?)
Je ne sais pas.
James Kanze a écrit :
> La solution évidente, c'est de ne jamais faire operator== un
> template. Faute d'autres solutions :
> template< typename T >
> class Generic
> {
> public:
> friend bool operator==( Generic const& lhs, Generic const&
> rhs )
> {
> return true /* ou d'autre chose */ ;
> }
> } ;
> (Du coup, l'operator== n'est pas un template. Mais il y en a
> autant qu'il faut.)
Oui, ca marche, mais c'est quand meme subtil: on utilise le
friend non pas pour donner l'accès aux membres proteges/prives
de Generic, mais pour rendre operator== non template... Bref,
c'est pas evident a la premiere lecture.
> Pour std::string, évidement, il n'y a rien que tu puisses
> faire.
Et c'est bien mon probleme...
> (Une question intéressante : est-ce qu'une implémentation de
> std::basic_string a le droit de faire comme ci-dessus ?)
Je ne sais pas.
James Kanze a écrit :
> La solution évidente, c'est de ne jamais faire operator== un
> template. Faute d'autres solutions :
> template< typename T >
> class Generic
> {
> public:
> friend bool operator==( Generic const& lhs, Generic const&
> rhs )
> {
> return true /* ou d'autre chose */ ;
> }
> } ;
> (Du coup, l'operator== n'est pas un template. Mais il y en a
> autant qu'il faut.)
Oui, ca marche, mais c'est quand meme subtil: on utilise le
friend non pas pour donner l'accès aux membres proteges/prives
de Generic, mais pour rendre operator== non template... Bref,
c'est pas evident a la premiere lecture.
> Pour std::string, évidement, il n'y a rien que tu puisses
> faire.
Et c'est bien mon probleme...
> (Une question intéressante : est-ce qu'une implémentation de
> std::basic_string a le droit de faire comme ci-dessus ?)
Je ne sais pas.