J'ai le cas d'avoir =E0 appliquer une op=E9ration g=E9n=E9rqie qui marche d=
ans
le cas g=E9n=E9ral et pas dans des cas particulier. Donc j'ai utilis=E9 le
syst=E8me classique surcharge:
Et puis les cas particuliers:
void fun(Bar1* b)
{
bar(b);
}
Mais maintenant, j'aurais besoin d'appliquer la fonction quand le type
d'entr=E9e a une certaine interface:
void fun(Itf* i)
{
toto(i);
}
Avec par exemple:
struct B: Itf{}
B b;
fun(&b);
Seulement, la fonction template est toujours le meilleur candidat =E0 la
r=E9solution de la surcharge.
Id=E9alement, j'aimerais un m=E9chanisme simple qui permette =E0 un
utilisateur de d=E9finir l'op=E9ration pour sa classe de types. C'est =E0
dire qu'il n'ait =E0 d=E9finir qu'une fois sont interface et la surcharge
de fun().
Toutes les solutions que j'ai envisag=E9es =E0 coup de m=E9ta-programmation
me semblent laides.
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Fabien LE LEZ
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez :
Idéalement, j'aimerais un méchanisme simple qui permette à un utilisateur de définir l'opération pour sa classe de types. C'est à dire qu'il n'ait à définir qu'une fois sont interface et la surcharge de fun().
Typiquement, on utilise des traits pour ça, non ?
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez
<michael.doubez@free.fr>:
Idéalement, j'aimerais un méchanisme simple qui permette à un
utilisateur de définir l'opération pour sa classe de types. C'est à
dire qu'il n'ait à définir qu'une fois sont interface et la surcharge
de fun().
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez :
Idéalement, j'aimerais un méchanisme simple qui permette à un utilisateur de définir l'opération pour sa classe de types. C'est à dire qu'il n'ait à définir qu'une fois sont interface et la surcharge de fun().
Typiquement, on utilise des traits pour ça, non ?
Fabien LE LEZ
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez :
fun(&b);
Ch'tite question en passant : pourquoi utiliser des pointeurs et pas des références ?
Toutes les solutions que j'ai envisagées à coup de méta-programmation me semblent laides.
Celle-là n'est pas beaucoup plus belle, et je ne sais même pas si elle fonctionne, mais bon, allons-y :
template <class T> void fun_impl (T* ptr, ...) // 1 { // le cas général }
template <class T> void fun_impl (T* ptr, Itf*) // 2 { // le cas spécial }
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres possibilités. Donc, si ptr est convertible en un Itf*, la version (2) est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez
<michael.doubez@free.fr>:
fun(&b);
Ch'tite question en passant : pourquoi utiliser des pointeurs et pas
des références ?
Toutes les solutions que j'ai envisagées à coup de méta-programmation
me semblent laides.
Celle-là n'est pas beaucoup plus belle, et je ne sais même pas si elle
fonctionne, mais bon, allons-y :
template <class T> void fun_impl (T* ptr, ...) // 1
{
// le cas général
}
template <class T> void fun_impl (T* ptr, Itf*) // 2
{
// le cas spécial
}
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres
possibilités. Donc, si ptr est convertible en un Itf*, la version (2)
est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
template <class T> void fun_impl (T* ptr, ...) // 1 { // le cas général }
template <class T> void fun_impl (T* ptr, Itf*) // 2 { // le cas spécial }
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres possibilités. Donc, si ptr est convertible en un Itf*, la version (2) est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
Michael Doubez
On 26 jan, 12:48, Fabien LE LEZ wrote:
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez :
>fun(&b);
Ch'tite question en passant : pourquoi utiliser des pointeurs et pas des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas moi qui ai décidé l'interface.
Le fait est que le cas général est composé de classes orthogonales qu e je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu marcher mais je retombe sur le même problème: template<class T, class Traits = FunTraits<T> > void fun(T* t) { Traits::fun(t); }
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
>Toutes les solutions que j'ai envisagées à coup de méta-programmat ion >me semblent laides.
Celle-là n'est pas beaucoup plus belle, et je ne sais même pas si ell e fonctionne, mais bon, allons-y :
template <class T> void fun_impl (T* ptr, ...) // 1 { // le cas général
}
template <class T> void fun_impl (T* ptr, Itf*) // 2 { // le cas spécial
}
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres possibilités. Donc, si ptr est convertible en un Itf*, la version (2) est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
Je ne vois pas comment je peux échapper à l'indirection supplémentaire.
Les classes orthogonales sont dans leur propre namespace, je pourrait peut être jouer la dessus mais je connais pas assez bien la résolution de nom pour savoir si ça peut résoudre mon best match dans la resolution de nom.
La version template ratisse trop large. Si tout rate, il me reste mes petites mains et définir la surcharge pour chacune des classes orthogonales.
-- Michael
On 26 jan, 12:48, Fabien LE LEZ <grams...@gramster.com> wrote:
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez
<michael.dou...@free.fr>:
>fun(&b);
Ch'tite question en passant : pourquoi utiliser des pointeurs et pas
des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas moi qui
ai décidé l'interface.
Le fait est que le cas général est composé de classes orthogonales qu e
je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu marcher
mais je retombe sur le même problème:
template<class T, class Traits = FunTraits<T> >
void fun(T* t)
{
Traits::fun(t);
}
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
>Toutes les solutions que j'ai envisagées à coup de méta-programmat ion
>me semblent laides.
Celle-là n'est pas beaucoup plus belle, et je ne sais même pas si ell e
fonctionne, mais bon, allons-y :
template <class T> void fun_impl (T* ptr, ...) // 1
{
// le cas général
}
template <class T> void fun_impl (T* ptr, Itf*) // 2
{
// le cas spécial
}
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres
possibilités. Donc, si ptr est convertible en un Itf*, la version (2)
est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
Je ne vois pas comment je peux échapper à l'indirection
supplémentaire.
Les classes orthogonales sont dans leur propre namespace, je pourrait
peut être jouer la dessus mais je connais pas assez bien la résolution
de nom pour savoir si ça peut résoudre mon best match dans la
resolution de nom.
La version template ratisse trop large. Si tout rate, il me reste mes
petites mains et définir la surcharge pour chacune des classes
orthogonales.
On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez :
>fun(&b);
Ch'tite question en passant : pourquoi utiliser des pointeurs et pas des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas moi qui ai décidé l'interface.
Le fait est que le cas général est composé de classes orthogonales qu e je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu marcher mais je retombe sur le même problème: template<class T, class Traits = FunTraits<T> > void fun(T* t) { Traits::fun(t); }
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
>Toutes les solutions que j'ai envisagées à coup de méta-programmat ion >me semblent laides.
Celle-là n'est pas beaucoup plus belle, et je ne sais même pas si ell e fonctionne, mais bon, allons-y :
template <class T> void fun_impl (T* ptr, ...) // 1 { // le cas général
}
template <class T> void fun_impl (T* ptr, Itf*) // 2 { // le cas spécial
}
L'idée : l'argument "..." n'est utilisé que s'il n'y a pas d'autres possibilités. Donc, si ptr est convertible en un Itf*, la version (2) est appelée. Sinon, c'est la version (1).
Rappel : un "Itf const*" n'est pas convertible en un "Itf*".
Je ne vois pas comment je peux échapper à l'indirection supplémentaire.
Les classes orthogonales sont dans leur propre namespace, je pourrait peut être jouer la dessus mais je connais pas assez bien la résolution de nom pour savoir si ça peut résoudre mon best match dans la resolution de nom.
La version template ratisse trop large. Si tout rate, il me reste mes petites mains et définir la surcharge pour chacune des classes orthogonales.
-- Michael
James Kanze
xOn Jan 26, 1:09 pm, Michael Doubez wrote:
On 26 jan, 12:48, Fabien LE LEZ wrote:
> On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez > :
> >fun(&b);
> Ch'tite question en passant : pourquoi utiliser des > pointeurs et pas des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas moi qui ai décidé l'interface.
Le fait est que le cas général est composé de classes orthogonales que je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu marcher mais je retombe sur le même problème: template<class T, class Traits = FunTraits<T> > void fun(T* t) { Traits::fun(t); }
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien quelque chose du genre :
(Enfin, c'est de tête. Il y a probablement pas mal de typos. Mais je me suis servi de quelque chose de semblable recemment, et ça a bien fonctionné. Dans la mesure où on n'essaie pas de l'instancier sur un type incomplet.)
-- James Kanze
xOn Jan 26, 1:09 pm, Michael Doubez <michael.dou...@free.fr> wrote:
On 26 jan, 12:48, Fabien LE LEZ <grams...@gramster.com> wrote:
> On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez
> <michael.dou...@free.fr>:
> >fun(&b);
> Ch'tite question en passant : pourquoi utiliser des
> pointeurs et pas des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas
moi qui ai décidé l'interface.
Le fait est que le cas général est composé de classes
orthogonales que je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu
marcher mais je retombe sur le même problème:
template<class T, class Traits = FunTraits<T> >
void fun(T* t)
{
Traits::fun(t);
}
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien
quelque chose du genre :
(Enfin, c'est de tête. Il y a probablement pas mal de typos.
Mais je me suis servi de quelque chose de semblable recemment,
et ça a bien fonctionné. Dans la mesure où on n'essaie pas de
l'instancier sur un type incomplet.)
> On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez > :
> >fun(&b);
> Ch'tite question en passant : pourquoi utiliser des > pointeurs et pas des références ?
Parce que dans le cas réel c'est un pointeur et que c'est pas moi qui ai décidé l'interface.
Le fait est que le cas général est composé de classes orthogonales que je ne peux pas modifier.
Comme tu l'as dis, une solution à base de traits aurait pu marcher mais je retombe sur le même problème: template<class T, class Traits = FunTraits<T> > void fun(T* t) { Traits::fun(t); }
FunTraits<T> va être la version générique.
Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien quelque chose du genre :
(Enfin, c'est de tête. Il y a probablement pas mal de typos. Mais je me suis servi de quelque chose de semblable recemment, et ça a bien fonctionné. Dans la mesure où on n'essaie pas de l'instancier sur un type incomplet.)
-- James Kanze
Fabien LE LEZ
On Tue, 26 Jan 2010 16:29:01 -0800 (PST), James Kanze :
J'y avais pensé aussi, mais il me semble que l'OP souhaite que l'utilisateur puisse définir ses propres fonctions fun() spécialisées.
Michael Doubez
On 27 jan, 01:29, James Kanze wrote:
xOn Jan 26, 1:09 pm, Michael Doubez wrote:
> On 26 jan, 12:48, Fabien LE LEZ wrote: > > On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez > > : > > >fun(&b); > > Ch'tite question en passant : pourquoi utiliser des > > pointeurs et pas des références ? > Parce que dans le cas réel c'est un pointeur et que c'est pas > moi qui ai décidé l'interface. > Le fait est que le cas général est composé de classes > orthogonales que je ne peux pas modifier. > Comme tu l'as dis, une solution à base de traits aurait pu > marcher mais je retombe sur le même problème: > template<class T, class Traits = FunTraits<T> > > void fun(T* t) > { > Traits::fun(t); > } > FunTraits<T> va être la version générique. > Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien quelque chose du genre :
template< typename T > void funcHelper( T* obj, Discriminator< false >) { // cas générique }
template< typename T > void func( T* obj ) { funcHelper( obj, Discriminator< DerivesFrom< T, MyBase>:: value >() );
}
(Enfin, c'est de tête. Il y a probablement pas mal de typos. Mais je me suis servi de quelque chose de semblable recemment, et ça a bien fonctionné. Dans la mesure où on n'essaie pas de l'instancier sur un type incomplet.)
Oui. J'avais envisagé d'utiliser cette technique mais ça ne permet de discriminer qu'un seul héritage et les solutions plus complexes ne sont pas vraiment user-friendly.
En réalité je souhaiterais que les règles de résolution s'appliquen t sans tenir compte de la version template et n'utilisent la version template qu'en dernier ressort. Et que la technique ne soit à faire que dans la version template.
Comme ça je peux écrire: void fun(Interface1* itf) { // cette fonction s'applique à tout objet d'une classe dérivée de Interface1 }
void fun(Interface2* itf) { // cette fonction s'applique à tout objet d'une classe dérivée de Interface2 }
template<class T> void fun(T* itf) { // cette fonction s'applique si il n'y a pas de match }
L'ideal serait de pouvoir utiliser void fun(...) { // cette fonction s'applique si il n'y a pas de meilleur match }
mais j'ai besoin du template.
Ton exemple m'a donné une idée, je pourrait jouer sur le type de retour de la fonction pour identifier si il y a un match:
// la suite de cette fonction s'applique si il n'y a pas de match }
-- Michael
On 27 jan, 01:29, James Kanze <james.ka...@gmail.com> wrote:
xOn Jan 26, 1:09 pm, Michael Doubez <michael.dou...@free.fr> wrote:
> On 26 jan, 12:48, Fabien LE LEZ <grams...@gramster.com> wrote:
> > On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez
> > <michael.dou...@free.fr>:
> > >fun(&b);
> > Ch'tite question en passant : pourquoi utiliser des
> > pointeurs et pas des références ?
> Parce que dans le cas réel c'est un pointeur et que c'est pas
> moi qui ai décidé l'interface.
> Le fait est que le cas général est composé de classes
> orthogonales que je ne peux pas modifier.
> Comme tu l'as dis, une solution à base de traits aurait pu
> marcher mais je retombe sur le même problème:
> template<class T, class Traits = FunTraits<T> >
> void fun(T* t)
> {
> Traits::fun(t);
> }
> FunTraits<T> va être la version générique.
> Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien
quelque chose du genre :
template< typename T >
void funcHelper( T* obj, Discriminator< false >)
{
// cas générique
}
template< typename T >
void func( T* obj )
{
funcHelper( obj, Discriminator< DerivesFrom< T, MyBase>:: value >() );
}
(Enfin, c'est de tête. Il y a probablement pas mal de typos.
Mais je me suis servi de quelque chose de semblable recemment,
et ça a bien fonctionné. Dans la mesure où on n'essaie pas de
l'instancier sur un type incomplet.)
Oui. J'avais envisagé d'utiliser cette technique mais ça ne permet de
discriminer qu'un seul héritage et les solutions plus complexes ne
sont pas vraiment user-friendly.
En réalité je souhaiterais que les règles de résolution s'appliquen t
sans tenir compte de la version template et n'utilisent la version
template qu'en dernier ressort. Et que la technique ne soit à faire
que dans la version template.
Comme ça je peux écrire:
void fun(Interface1* itf)
{
// cette fonction s'applique à tout objet d'une classe dérivée de
Interface1
}
void fun(Interface2* itf)
{
// cette fonction s'applique à tout objet d'une classe dérivée de
Interface2
}
template<class T>
void fun(T* itf)
{
// cette fonction s'applique si il n'y a pas de match
}
L'ideal serait de pouvoir utiliser
void fun(...)
{
// cette fonction s'applique si il n'y a pas de meilleur match
}
mais j'ai besoin du template.
Ton exemple m'a donné une idée, je pourrait jouer sur le type de
retour de la fonction pour identifier si il y a un match:
> On 26 jan, 12:48, Fabien LE LEZ wrote: > > On Tue, 26 Jan 2010 03:22:15 -0800 (PST), Michael Doubez > > : > > >fun(&b); > > Ch'tite question en passant : pourquoi utiliser des > > pointeurs et pas des références ? > Parce que dans le cas réel c'est un pointeur et que c'est pas > moi qui ai décidé l'interface. > Le fait est que le cas général est composé de classes > orthogonales que je ne peux pas modifier. > Comme tu l'as dis, une solution à base de traits aurait pu > marcher mais je retombe sur le même problème: > template<class T, class Traits = FunTraits<T> > > void fun(T* t) > { > Traits::fun(t); > } > FunTraits<T> va être la version générique. > Et pas question de mettre les traits dans la classe.
Rien n'exige que les traits soit dans la classe. Je verrais bien quelque chose du genre :
template< typename T > void funcHelper( T* obj, Discriminator< false >) { // cas générique }
template< typename T > void func( T* obj ) { funcHelper( obj, Discriminator< DerivesFrom< T, MyBase>:: value >() );
}
(Enfin, c'est de tête. Il y a probablement pas mal de typos. Mais je me suis servi de quelque chose de semblable recemment, et ça a bien fonctionné. Dans la mesure où on n'essaie pas de l'instancier sur un type incomplet.)
Oui. J'avais envisagé d'utiliser cette technique mais ça ne permet de discriminer qu'un seul héritage et les solutions plus complexes ne sont pas vraiment user-friendly.
En réalité je souhaiterais que les règles de résolution s'appliquen t sans tenir compte de la version template et n'utilisent la version template qu'en dernier ressort. Et que la technique ne soit à faire que dans la version template.
Comme ça je peux écrire: void fun(Interface1* itf) { // cette fonction s'applique à tout objet d'une classe dérivée de Interface1 }
void fun(Interface2* itf) { // cette fonction s'applique à tout objet d'une classe dérivée de Interface2 }
template<class T> void fun(T* itf) { // cette fonction s'applique si il n'y a pas de match }
L'ideal serait de pouvoir utiliser void fun(...) { // cette fonction s'applique si il n'y a pas de meilleur match }
mais j'ai besoin du template.
Ton exemple m'a donné une idée, je pourrait jouer sur le type de retour de la fonction pour identifier si il y a un match: