Bonsoir Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite, c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do' "n'hérite" de la classe B ou A ou C. la garantie serait plus comment s'assurer que la méthode Do reçoit un paramètre donnée. votre question est donc: comment définir une fonction paramétrable qui n'accepte qu'un un seul type de paramètre donné ?!
êtes-vous sur que cela a du sens ? ou que votre contrainte est clairement expliquée ?
Sylvain.
jeremie fouche wrote on 09/05/2008 00:21:
Bonsoir
Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite,
c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do'
"n'hérite" de la classe B ou A ou C. la garantie serait plus
comment s'assurer que la méthode Do reçoit un paramètre donnée.
votre question est donc: comment définir une fonction paramétrable
qui n'accepte qu'un un seul type de paramètre donné ?!
êtes-vous sur que cela a du sens ? ou que votre contrainte est
clairement expliquée ?
Bonsoir Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite, c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do' "n'hérite" de la classe B ou A ou C. la garantie serait plus comment s'assurer que la méthode Do reçoit un paramètre donnée. votre question est donc: comment définir une fonction paramétrable qui n'accepte qu'un un seul type de paramètre donné ?!
êtes-vous sur que cela a du sens ? ou que votre contrainte est clairement expliquée ?
Sylvain.
jeremie fouche
jeremie fouche wrote on 09/05/2008 00:21:
Bonsoir Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite, c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do' "n'hérite" de la classe B ou A ou C. la garantie serait plus comment s'assurer que la méthode Do reçoit un paramètre donnée. votre question est donc: comment définir une fonction paramétrable qui n'accepte qu'un un seul type de paramètre donné ?!
Absolument.
êtes-vous sur que cela a du sens ? ou que votre contrainte est clairement expliquée ?
Je pensais, avec l'exemple donné. Je souhaite refuser d'utiliser la méthode D::Do avec autre chose qu'une classe héritant de A. C'est plus pour apprendre, car aujourd'hui, en laissant le code tel quel, cela fonctionne correctement dans mon produit. Je voudrais juste savoir si c'est possible ou non. Merci pour le recadrage sur la question -- Jérémie
jeremie fouche wrote on 09/05/2008 00:21:
Bonsoir
Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite,
c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do'
"n'hérite" de la classe B ou A ou C. la garantie serait plus
comment s'assurer que la méthode Do reçoit un paramètre donnée.
votre question est donc: comment définir une fonction paramétrable
qui n'accepte qu'un un seul type de paramètre donné ?!
Absolument.
êtes-vous sur que cela a du sens ? ou que votre contrainte est
clairement expliquée ?
Je pensais, avec l'exemple donné.
Je souhaite refuser d'utiliser la méthode D::Do avec autre chose qu'une
classe héritant de A.
C'est plus pour apprendre, car aujourd'hui, en laissant le code tel
quel, cela fonctionne correctement dans mon produit. Je voudrais juste
savoir si c'est possible ou non.
Merci pour le recadrage sur la question
--
Jérémie
Bonsoir Je ne savais pas trop quel titre donner à mon post. Ce que je souhaite, c'est assurer qu'un membre template hérite d'une classe donnée.
dans votre exemple, ni la classe D, ni sa fonction membre 'Do' "n'hérite" de la classe B ou A ou C. la garantie serait plus comment s'assurer que la méthode Do reçoit un paramètre donnée. votre question est donc: comment définir une fonction paramétrable qui n'accepte qu'un un seul type de paramètre donné ?!
Absolument.
êtes-vous sur que cela a du sens ? ou que votre contrainte est clairement expliquée ?
Je pensais, avec l'exemple donné. Je souhaite refuser d'utiliser la méthode D::Do avec autre chose qu'une classe héritant de A. C'est plus pour apprendre, car aujourd'hui, en laissant le code tel quel, cela fonctionne correctement dans mon produit. Je voudrais juste savoir si c'est possible ou non. Merci pour le recadrage sur la question -- Jérémie
Fabien LE LEZ
On Fri, 09 May 2008 00:21:26 +0200, jeremie fouche :
void Do(void)
Note en passant : le deuxième "void" est totalement inutile, et typique d'un code en C. En C++ on écrira plutôt :
void Do()
class B : public A Do<B>(); // OK, ca doit compiler Do<A>(); // ne doit pas compiler Do<C>(); // ne doit pas compiler
En résumé :
- si T = A, erreur de compilation - sinon, si T dérive de A, OK - sinon, erreur
C'est bien ça ?
Ça ressemble fort aux sections 2.7 et 2.1 de "Modern C++ Design" (Alexandrescu).
Apparemment que le code suivant répond à la question :
#include "static_check.h" #include "TypeManip.h"
class D { public: void Test() { Do<B>(); // OK, ca doit compiler //Do<A>(); // ne doit pas compiler //Do<C>(); // ne doit pas compiler }
Les deux .h se trouvent dans Loki. La version d'origine (basée sur le livre, et sur laquelle se base le code ci-dessus) se trouve à l'adresse <http://www.awprofessional.com/content/images/0201704315/sourcecode/loki.zip>. Pour le reste, cf <http://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29>.
On Fri, 09 May 2008 00:21:26 +0200, jeremie fouche <jfouche@voila.fr>:
void Do(void)
Note en passant : le deuxième "void" est totalement inutile, et
typique d'un code en C. En C++ on écrira plutôt :
void Do()
class B : public A
Do<B>(); // OK, ca doit compiler
Do<A>(); // ne doit pas compiler
Do<C>(); // ne doit pas compiler
En résumé :
- si T = A, erreur de compilation
- sinon, si T dérive de A, OK
- sinon, erreur
C'est bien ça ?
Ça ressemble fort aux sections 2.7 et 2.1 de "Modern C++ Design"
(Alexandrescu).
Apparemment que le code suivant répond à la question :
#include "static_check.h"
#include "TypeManip.h"
class D
{
public:
void Test()
{
Do<B>(); // OK, ca doit compiler
//Do<A>(); // ne doit pas compiler
//Do<C>(); // ne doit pas compiler
}
Les deux .h se trouvent dans Loki.
La version d'origine (basée sur le livre, et sur laquelle se base le
code ci-dessus) se trouve à l'adresse
<http://www.awprofessional.com/content/images/0201704315/sourcecode/loki.zip>.
Pour le reste, cf <http://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29>.
Les deux .h se trouvent dans Loki. La version d'origine (basée sur le livre, et sur laquelle se base le code ci-dessus) se trouve à l'adresse <http://www.awprofessional.com/content/images/0201704315/sourcecode/loki.zip>. Pour le reste, cf <http://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29>.
Fabien LE LEZ
On Fri, 09 May 2008 00:44:51 +0200, jeremie fouche :
Je souhaite refuser d'utiliser la méthode D::Do avec autre chose qu'une classe héritant de A.
Là où j'ai du mal à comprendre le sens, c'est que tu acceptes B mais refuses A.
On Fri, 09 May 2008 00:44:51 +0200, jeremie fouche <jfouche@voila.fr>:
Je souhaite refuser d'utiliser la méthode D::Do avec autre chose qu'une
classe héritant de A.
Là où j'ai du mal à comprendre le sens, c'est que tu acceptes B mais
refuses A.
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ? (j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé par STATIC_CHECK pour comparer ses 2 membres ?)
je pensais bien à un typeid mais les infos ne sont disponibles
qu'au runtime pas à la compil., c'est le cas ici ?
(j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé
par STATIC_CHECK pour comparer ses 2 membres ?)
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ? (j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé par STATIC_CHECK pour comparer ses 2 membres ?)
Sylvain.
Sylvain SF
Sylvain SF wrote on 09/05/2008 02:09:
c'est le cas ici ?
j'ai trouvé mes réponses ... et je ne les ai pas comprises!
Sylvain.
Sylvain SF wrote on 09/05/2008 02:09:
c'est le cas ici ?
j'ai trouvé mes réponses ... et je ne les ai pas comprises!
j'ai trouvé mes réponses ... et je ne les ai pas comprises!
Sylvain.
Fabien LE LEZ
On Fri, 09 May 2008 02:09:53 +0200, "Sylvain SF" :
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ?
Non, non, ici tout est statique. L'OP voulait un système tel que la ligne "Do<B>();" compile, et les lignes "Do<A>();" et "Do<C>();" ne compilent pas. C'est le cas : les deux derniers déclenchent une erreur de compilation.
"SUPERSUBCLASS_STRICT (A, T)" est une valeur, calculée par le compilateur, égale à 1 si T dérive (strictement) de A, et à 0 sinon.
"STATIC_CHECK (true, ..." est une no-op. "STATIC_CHECK (false, ..." est un code incorrect.
En fait, on pourrait l'implémenter comme ceci :
#define STATIC_CHECK(x) { char dummy[x]; } Si x vaut 0, le code n'est pas correct, et le compilo râle ; si x>0, ce code ne fait rien d'utile.
C'est très différent de assert(x), qui ne déclenche jamais d'erreur de compilation (mais peut parfois arrêter le programme à l'exécution.)
"T_doit_deriver_de_A" correspond à quoi ?
C'est censé être le message d'erreur qui s'affiche. En pratique, ça ne semble pas fonctionner (avec Comeau), et je n'ai pas trop le courage d'aller voir pourquoi. Tu peux mettre n'importe quel identifiant à la place.
En passant, je rappelle que tout ça sort du bouquin "Modern C++ Design" (Alexandrescu), dont je conseille fortement la lecture. C'est le livre qui m'a fait réellement comprendre toute la puissance des templates.
On Fri, 09 May 2008 02:09:53 +0200, "Sylvain SF" :
je pensais bien à un typeid mais les infos ne sont disponibles
qu'au runtime pas à la compil., c'est le cas ici ?
Non, non, ici tout est statique.
L'OP voulait un système tel que la ligne "Do<B>();" compile, et les
lignes "Do<A>();" et "Do<C>();" ne compilent pas. C'est le cas : les
deux derniers déclenchent une erreur de compilation.
"SUPERSUBCLASS_STRICT (A, T)" est une valeur, calculée par le
compilateur, égale à 1 si T dérive (strictement) de A, et à 0 sinon.
"STATIC_CHECK (true, ..." est une no-op.
"STATIC_CHECK (false, ..." est un code incorrect.
En fait, on pourrait l'implémenter comme ceci :
#define STATIC_CHECK(x) { char dummy[x]; }
Si x vaut 0, le code n'est pas correct, et le compilo râle ; si x>0,
ce code ne fait rien d'utile.
C'est très différent de assert(x), qui ne déclenche jamais d'erreur de
compilation (mais peut parfois arrêter le programme à l'exécution.)
"T_doit_deriver_de_A" correspond à quoi ?
C'est censé être le message d'erreur qui s'affiche. En pratique, ça ne
semble pas fonctionner (avec Comeau), et je n'ai pas trop le courage
d'aller voir pourquoi.
Tu peux mettre n'importe quel identifiant à la place.
En passant, je rappelle que tout ça sort du bouquin "Modern C++
Design" (Alexandrescu), dont je conseille fortement la lecture. C'est
le livre qui m'a fait réellement comprendre toute la puissance des
templates.
On Fri, 09 May 2008 02:09:53 +0200, "Sylvain SF" :
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ?
Non, non, ici tout est statique. L'OP voulait un système tel que la ligne "Do<B>();" compile, et les lignes "Do<A>();" et "Do<C>();" ne compilent pas. C'est le cas : les deux derniers déclenchent une erreur de compilation.
"SUPERSUBCLASS_STRICT (A, T)" est une valeur, calculée par le compilateur, égale à 1 si T dérive (strictement) de A, et à 0 sinon.
"STATIC_CHECK (true, ..." est une no-op. "STATIC_CHECK (false, ..." est un code incorrect.
En fait, on pourrait l'implémenter comme ceci :
#define STATIC_CHECK(x) { char dummy[x]; } Si x vaut 0, le code n'est pas correct, et le compilo râle ; si x>0, ce code ne fait rien d'utile.
C'est très différent de assert(x), qui ne déclenche jamais d'erreur de compilation (mais peut parfois arrêter le programme à l'exécution.)
"T_doit_deriver_de_A" correspond à quoi ?
C'est censé être le message d'erreur qui s'affiche. En pratique, ça ne semble pas fonctionner (avec Comeau), et je n'ai pas trop le courage d'aller voir pourquoi. Tu peux mettre n'importe quel identifiant à la place.
En passant, je rappelle que tout ça sort du bouquin "Modern C++ Design" (Alexandrescu), dont je conseille fortement la lecture. C'est le livre qui m'a fait réellement comprendre toute la puissance des templates.
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ? (j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé par STATIC_CHECK pour comparer ses 2 membres ?)
Je te conseille le Vandevoorde et Josuttis : il décrit en détail ce genre de chose, et c'est extrèmement bien écrit. Dans ce cas-ci, grosso modo :
La principe de base, c'est de se servir de la résolution du surcharge des fonctions (dont des fonctions templatées) pour choisir selon les caractèristiques du type. Mais évidemment, on ne veut pas réelement appeler les fonctions, ce qui de toute façon ne se fera que lors de l'exécution. L'astuce, ici, c'est de se servir de sizeof pour obtenir une constante de compilation qui dépend de la résolution du surcharge : sizeof( func(...) ) vaut la taille du type du rétour de la fonction, et le compilateur effectue bien la résolution du surcharge sans jamais appeler la fonction.
Alors, pour commencer, on a besoin de deux types de taille garantie différente, donc :
Note que c'est moins évident qu'on pourrait penser, parce que la taille renvoyée par sizeof comprend un éventuel rembourrage nécessaire pour l'alignement, et que la norme impose bien peu de contraints sur les tailles rélatives. Ceci est la solution classique, et je crois que c'est garanti, du fait que dans TrueType, l'adresse de dummy[1] doit bien être &dummy[0]+1.
Ensuite, il faut définir l'ensemble des fonctions pour discriminer ; commençons par un cas ultrasimple, où tu exiges A ou dérivé d'A :
Note bien que si tu instancies SeulementDeriveeD_A avec A, ou une classe dérivée d'A, la résolution du surcharge dans la définition de dummy va choisir la deuxième déclaration de discrimintator, sinon la première. Note bien aussi le choix de paramètres formels et l'expression du paramètre réel. On fait attention d'éviter le moindre exigeance supplémentaire, genre copiable, ou un constructeur sans paramètres. Si on peut initialiser un A* avec un T*, le compilateur choisit discrimintator( A* ), parce que tout autre choix est préférable à utiliser le ... Du coup, le sizeof renvoie quelque chose supérieur à 1, et le code reste légal. Si l'appel de discrimintator( A* ) n'est pas légal avec un T*, le compilateur n'a pas le choix, il choisit discrimintator( ... ), le sizeof renvoie 1, on retranche 1, et on a une déclaration d'un tableau à taille 0. Et donc, une erreur à la compilation.
Ici, j'ai laissé la déclaration dans la classe même, pour rester simple. Ce qui augment la taille de la classe. La plupart du temps, on cherche à éviter cette augmentation de taille en cachant la déclaration ailleurs, mais dans quelque chose qui est certain d'être instantié lors de l'instantiation de la classe. La plus sûr, c'est probablement de le coller dans une union anonyme avec un autre élément de la classe -- une autre solution fréquente, c'est de le mettre dans une fonction inline qui est appelée dans le destructeur (ce qui permet encore des déclarations des pointeurs aux types non voulus, mais déclenche une erreur dès qu'il y a un objet du type).
Enfin, on est prèsque arrivé où tu voulais. Il ne reste qu'à écarter le cas où la classe est la classe de base même. Et c'est assez facile à tester pour une classe précise :
Pour tout type sauf A, l'instantiation du template correspondrait exactement, tandis que la deuxième déclaration exigera une conversion. C'est donc l'instantiation du template qui est choisi. Pour A même, les deux correspond exactement, et quand le compilateur a à choisir entre deux fonctions qui correspond de la même dégrée, c'est le non-template qui a précédance sur le template.
Finalement, on cherche à jouer avec le nom de la variable, etc., pour avoir quelque chose dans le message d'erreur qui donne une indication d'où se trouve la vraie erreur. Mais vue les variations dans les messages d'erreur, ce n'est pas toujours évident.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
On May 9, 2:09 am, "Sylvain SF" <sylv...@boiteaspam.info> wrote:
je pensais bien à un typeid mais les infos ne sont disponibles
qu'au runtime pas à la compil., c'est le cas ici ?
(j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé
par STATIC_CHECK pour comparer ses 2 membres ?)
Je te conseille le Vandevoorde et Josuttis : il décrit en
détail ce genre de chose, et c'est extrèmement bien écrit. Dans
ce cas-ci, grosso modo :
La principe de base, c'est de se servir de la résolution du
surcharge des fonctions (dont des fonctions templatées) pour
choisir selon les caractèristiques du type. Mais évidemment, on
ne veut pas réelement appeler les fonctions, ce qui de toute
façon ne se fera que lors de l'exécution. L'astuce, ici, c'est
de se servir de sizeof pour obtenir une constante de compilation
qui dépend de la résolution du surcharge : sizeof( func(...) )
vaut la taille du type du rétour de la fonction, et le
compilateur effectue bien la résolution du surcharge sans jamais
appeler la fonction.
Alors, pour commencer, on a besoin de deux types de taille
garantie différente, donc :
Note que c'est moins évident qu'on pourrait penser, parce que
la taille renvoyée par sizeof comprend un éventuel rembourrage
nécessaire pour l'alignement, et que la norme impose bien peu de
contraints sur les tailles rélatives. Ceci est la solution
classique, et je crois que c'est garanti, du fait que dans
TrueType, l'adresse de dummy[1] doit bien être &dummy[0]+1.
Ensuite, il faut définir l'ensemble des fonctions pour
discriminer ; commençons par un cas ultrasimple, où tu exiges A
ou dérivé d'A :
Note bien que si tu instancies SeulementDeriveeD_A avec A, ou
une classe dérivée d'A, la résolution du surcharge dans la
définition de dummy va choisir la deuxième déclaration de
discrimintator, sinon la première. Note bien aussi le choix de
paramètres formels et l'expression du paramètre réel. On fait
attention d'éviter le moindre exigeance supplémentaire, genre
copiable, ou un constructeur sans paramètres. Si on peut
initialiser un A* avec un T*, le compilateur choisit
discrimintator( A* ), parce que tout autre choix est préférable
à utiliser le ... Du coup, le sizeof renvoie quelque chose
supérieur à 1, et le code reste légal. Si l'appel de
discrimintator( A* ) n'est pas légal avec un T*, le compilateur
n'a pas le choix, il choisit discrimintator( ... ), le sizeof
renvoie 1, on retranche 1, et on a une déclaration d'un tableau
à taille 0. Et donc, une erreur à la compilation.
Ici, j'ai laissé la déclaration dans la classe même, pour rester
simple. Ce qui augment la taille de la classe. La plupart du
temps, on cherche à éviter cette augmentation de taille en
cachant la déclaration ailleurs, mais dans quelque chose qui est
certain d'être instantié lors de l'instantiation de la classe.
La plus sûr, c'est probablement de le coller dans une union
anonyme avec un autre élément de la classe -- une autre
solution fréquente, c'est de le mettre dans une fonction inline
qui est appelée dans le destructeur (ce qui permet encore des
déclarations des pointeurs aux types non voulus, mais déclenche
une erreur dès qu'il y a un objet du type).
Enfin, on est prèsque arrivé où tu voulais. Il ne reste qu'à
écarter le cas où la classe est la classe de base même. Et c'est
assez facile à tester pour une classe précise :
Pour tout type sauf A, l'instantiation du template
correspondrait exactement, tandis que la deuxième déclaration
exigera une conversion. C'est donc l'instantiation du template
qui est choisi. Pour A même, les deux correspond exactement, et
quand le compilateur a à choisir entre deux fonctions qui
correspond de la même dégrée, c'est le non-template qui a
précédance sur le template.
Finalement, on cherche à jouer avec le nom de la variable, etc.,
pour avoir quelque chose dans le message d'erreur qui donne une
indication d'où se trouve la vraie erreur. Mais vue les
variations dans les messages d'erreur, ce n'est pas toujours
évident.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
je pensais bien à un typeid mais les infos ne sont disponibles qu'au runtime pas à la compil., c'est le cas ici ? (j'ai parcouru le wiki mais pas éplucher tout le zip).
"T_doit_deriver_de_A" correspond à quoi ? (juste un bool utilisé par STATIC_CHECK pour comparer ses 2 membres ?)
Je te conseille le Vandevoorde et Josuttis : il décrit en détail ce genre de chose, et c'est extrèmement bien écrit. Dans ce cas-ci, grosso modo :
La principe de base, c'est de se servir de la résolution du surcharge des fonctions (dont des fonctions templatées) pour choisir selon les caractèristiques du type. Mais évidemment, on ne veut pas réelement appeler les fonctions, ce qui de toute façon ne se fera que lors de l'exécution. L'astuce, ici, c'est de se servir de sizeof pour obtenir une constante de compilation qui dépend de la résolution du surcharge : sizeof( func(...) ) vaut la taille du type du rétour de la fonction, et le compilateur effectue bien la résolution du surcharge sans jamais appeler la fonction.
Alors, pour commencer, on a besoin de deux types de taille garantie différente, donc :
Note que c'est moins évident qu'on pourrait penser, parce que la taille renvoyée par sizeof comprend un éventuel rembourrage nécessaire pour l'alignement, et que la norme impose bien peu de contraints sur les tailles rélatives. Ceci est la solution classique, et je crois que c'est garanti, du fait que dans TrueType, l'adresse de dummy[1] doit bien être &dummy[0]+1.
Ensuite, il faut définir l'ensemble des fonctions pour discriminer ; commençons par un cas ultrasimple, où tu exiges A ou dérivé d'A :
Note bien que si tu instancies SeulementDeriveeD_A avec A, ou une classe dérivée d'A, la résolution du surcharge dans la définition de dummy va choisir la deuxième déclaration de discrimintator, sinon la première. Note bien aussi le choix de paramètres formels et l'expression du paramètre réel. On fait attention d'éviter le moindre exigeance supplémentaire, genre copiable, ou un constructeur sans paramètres. Si on peut initialiser un A* avec un T*, le compilateur choisit discrimintator( A* ), parce que tout autre choix est préférable à utiliser le ... Du coup, le sizeof renvoie quelque chose supérieur à 1, et le code reste légal. Si l'appel de discrimintator( A* ) n'est pas légal avec un T*, le compilateur n'a pas le choix, il choisit discrimintator( ... ), le sizeof renvoie 1, on retranche 1, et on a une déclaration d'un tableau à taille 0. Et donc, une erreur à la compilation.
Ici, j'ai laissé la déclaration dans la classe même, pour rester simple. Ce qui augment la taille de la classe. La plupart du temps, on cherche à éviter cette augmentation de taille en cachant la déclaration ailleurs, mais dans quelque chose qui est certain d'être instantié lors de l'instantiation de la classe. La plus sûr, c'est probablement de le coller dans une union anonyme avec un autre élément de la classe -- une autre solution fréquente, c'est de le mettre dans une fonction inline qui est appelée dans le destructeur (ce qui permet encore des déclarations des pointeurs aux types non voulus, mais déclenche une erreur dès qu'il y a un objet du type).
Enfin, on est prèsque arrivé où tu voulais. Il ne reste qu'à écarter le cas où la classe est la classe de base même. Et c'est assez facile à tester pour une classe précise :
Pour tout type sauf A, l'instantiation du template correspondrait exactement, tandis que la deuxième déclaration exigera une conversion. C'est donc l'instantiation du template qui est choisi. Pour A même, les deux correspond exactement, et quand le compilateur a à choisir entre deux fonctions qui correspond de la même dégrée, c'est le non-template qui a précédance sur le template.
Finalement, on cherche à jouer avec le nom de la variable, etc., pour avoir quelque chose dans le message d'erreur qui donne une indication d'où se trouve la vraie erreur. Mais vue les variations dans les messages d'erreur, ce n'est pas toujours évident.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
jeremie fouche
On Fri, 09 May 2008 00:21:26 +0200, jeremie fouche :
void Do(void)
Note en passant : le deuxième "void" est totalement inutile, et typique d'un code en C. En C++ on écrira plutôt :
ET oui, je sais bien, tu me l'as déjà expliqué, mais les habitudes ont (encore un peu) la vie dure. Note que j'ai réussi pour les autres ;)
En résumé :
- si T = A, erreur de compilation - sinon, si T dérive de A, OK - sinon, erreur
C'est bien ça ?
Voui
Ça ressemble fort aux sections 2.7 et 2.1 de "Modern C++ Design" (Alexandrescu).
Apparemment que le code suivant répond à la question :...
Merci pour vos réponses En fait, je pensais qu'on pouvait faire un truc dans le genre sans passer par de gros trucs. -- Jérémie
On Fri, 09 May 2008 00:21:26 +0200, jeremie fouche <jfouche@voila.fr>:
void Do(void)
Note en passant : le deuxième "void" est totalement inutile, et
typique d'un code en C. En C++ on écrira plutôt :
ET oui, je sais bien, tu me l'as déjà expliqué, mais les habitudes ont
(encore un peu) la vie dure. Note que j'ai réussi pour les autres ;)
En résumé :
- si T = A, erreur de compilation
- sinon, si T dérive de A, OK
- sinon, erreur
C'est bien ça ?
Voui
Ça ressemble fort aux sections 2.7 et 2.1 de "Modern C++ Design"
(Alexandrescu).
Apparemment que le code suivant répond à la question :...
Merci pour vos réponses
En fait, je pensais qu'on pouvait faire un truc dans le genre sans
passer par de gros trucs.
--
Jérémie