Quelles sont les motivations qui peuvent me pousser à utiliser des
méthodes inline ?
Par exemple, j'ai une classe avec des membres privés dont je déclare des
accesseurs (getFoo, setFoo)
public:
int getFoo() const;
void setFoo(int value);
private:
int m_foot;
Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en
sachant que ce sont des fonctions au contenu trivial et petit (getFoo se
contente de renvoyer m_foot par exemple) ?
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
Le profiler a dit que ça ne va pas autrement.
C'est effectivement le conseil que j'ai lu le plus souvent à ce sujet. Mais quelles sont les indications concrètes que le profiler peut donner ? Il ne me semble pas que quantify, par exemple, puisse rapporter le coût de *l'appel* d'une fonction. Doit-on se baser sur le nombre d'appels à la fonction ?
Tout dépend du profiler, mais en gros, si tu trouves trop de temps dans toutes les fonctions qui utilisent ta fonction, ou surtout dans une fonction qui l'utilise dans une boucle, c'est un signe qu'il vaut la peine d'essayer.
-- James Kanze GABI Software 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
Bertrand Motuelle wrote:
kanze wrote:
none (none) wrote:
Quelles sont les motivations qui peuvent me pousser à utiliser
des méthodes inline ?
Le profiler a dit que ça ne va pas autrement.
C'est effectivement le conseil que j'ai lu le plus souvent à
ce sujet. Mais quelles sont les indications concrètes que le
profiler peut donner ? Il ne me semble pas que quantify, par
exemple, puisse rapporter le coût de *l'appel* d'une fonction.
Doit-on se baser sur le nombre d'appels à la fonction ?
Tout dépend du profiler, mais en gros, si tu trouves trop de
temps dans toutes les fonctions qui utilisent ta fonction, ou
surtout dans une fonction qui l'utilise dans une boucle, c'est
un signe qu'il vaut la peine d'essayer.
--
James Kanze GABI Software
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
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
Le profiler a dit que ça ne va pas autrement.
C'est effectivement le conseil que j'ai lu le plus souvent à ce sujet. Mais quelles sont les indications concrètes que le profiler peut donner ? Il ne me semble pas que quantify, par exemple, puisse rapporter le coût de *l'appel* d'une fonction. Doit-on se baser sur le nombre d'appels à la fonction ?
Tout dépend du profiler, mais en gros, si tu trouves trop de temps dans toutes les fonctions qui utilisent ta fonction, ou surtout dans une fonction qui l'utilise dans une boucle, c'est un signe qu'il vaut la peine d'essayer.
-- James Kanze GABI Software 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
kanze
Patrick 'Zener' Brunet wrote:
Je réponds à none" <""(none)"@(none) <""(none)"@(none)">
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ? Par exemple, j'ai une classe avec des membres privés dont je déclare des accesseurs (getFoo, setFoo)
public: int getFoo() const; void setFoo(int value); private: int m_foot;
Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en sachant que ce sont des fonctions au contenu trivial et petit (getFoo se contente de renvoyer m_foot par exemple) ?
Je crois que ça dépend déjà du contexte:
Un peu, certainement.
* Si vous développez une librairie, il peut être intéressant de proposer à votre utilisateur de choisir des fonctions (normalement) plus efficaces sans lui imposer de relire le code. Si vous êtes votre propre utilisateur, vous maîtrisez mieux les usages.
Si tu vends des bibliothèques, tu as effectivement le problème que tu n'as pas la possibilité d'effectuer du profiling sur les applications finales, pour savoir exactement où ça coince. Et si tu vends des bibliothèques de bas niveau, du genre bibliothèque standard ou certains composents de Boost, tu peux être prèsque sûr que parmi les clients, il y en aura un ou deux, au moins, où la performance va être importante. Tu seras donc amené à faire des optimisations (dont inline) sans avoir du feed-back d'un profiler -- si j'implémentais la bibliothèque standard, par exemple, std::vector<>::operator[] serait inline, dès le départ.
Mais les gens qui implémentent ce genre de bibliothèque sont assez rares, et ces arguments ne valent que pour eux.
* Ensuite il y a plusieurs profils de programmeurs: certains comptent sur le compilateur pour contrer leurs maladresses, alors que d'autres s'efforcent de programmer à la fois fiable et efficace. Parmi les seconds, certains y parviennent le plus souvent et d'autres se trompent.
Ce n'est pas une question de « contrer les maladresses ». C'est une question de laisser au compilateur faire ce qu'il sait faire de mieux, et surtout d'investir son effort où il rapporte le plus.
Il faut dire qu'en quinze ans de C++, en dehors des classes de bases comme vector et list (ou dans l'époque pré-standard, mon ArrayOf et DLListOf), je n'ai jamais rencontré un cas où inline a eu un effet mesurable sur la performance. Au contraire, les améliorations les plus importantes de la performance ont toujours été simplifiées du fait qu'on ne mettait rien inline ; pouvoir modifier l'algorithme et la structure de données d'a en z sans avoir à récompiler tous les utilisateurs est un avantage à ne pas negliger.
* Enfin il y a la qualité et "l'intelligence embarquée" du compilateur: certains sont capables de restructurer complètement le code, d'autres pas.
Donc AMHA, il n'y a pas de mal à mettre en place un maximum de précision dans son code, pour autant qu'elle soit réfléchie, et en sachant que le compilateur peut éventuellement la remettre en question.
Donc typiquement pour une fonction qui ainsi emballe simplement une ou deux instructions simples, ... faisant assez peu usage de la pile pour que son coût d'invocation (en nombre d'instructions) soit important par rapport au traitement lui-même, ... AMHA la déclaration inline est plutôt une amélioration.
Tu ne prends pas en compte son coût. Le fait qu'il rend tous les clients dépendants de son implémentation. Dans la plupart des cas, le coût est bien supérieur À n'importe quel avantage imaginé.
Mais donc ça nécessite d'avoir une certaine connaissance du protocole normal d'invocation sur le(s) système(s) visé(s).
C'est donc qu'en plus, ce n'est pas portable. (Je dirais qu'en général, on écrit du code sans trop savoir sur quelles machines il risque de tourner. Beaucoup de code que j'ai développé sur Sparc tourne aujourd'hui sous Linux sur PC ; c'était une évolution qu'on ne pouvait pas du tout prévoir quand je l'ai écrit.)
-- James Kanze GABI Software 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
Patrick 'Zener' Brunet wrote:
Je réponds à none" <""(none)"@(none) <""(none)"@(none)">
Quelles sont les motivations qui peuvent me pousser à
utiliser des méthodes inline ? Par exemple, j'ai une classe
avec des membres privés dont je déclare des accesseurs
(getFoo, setFoo)
public:
int getFoo() const;
void setFoo(int value);
private:
int m_foot;
Est-il judicieux de déclarer getFoo et setFoo en inline
d'emblée, en sachant que ce sont des fonctions au contenu
trivial et petit (getFoo se contente de renvoyer m_foot par
exemple) ?
Je crois que ça dépend déjà du contexte:
Un peu, certainement.
* Si vous développez une librairie, il peut être intéressant
de proposer à votre utilisateur de choisir des fonctions
(normalement) plus efficaces sans lui imposer de relire le
code. Si vous êtes votre propre utilisateur, vous maîtrisez
mieux les usages.
Si tu vends des bibliothèques, tu as effectivement le problème
que tu n'as pas la possibilité d'effectuer du profiling sur les
applications finales, pour savoir exactement où ça coince. Et si
tu vends des bibliothèques de bas niveau, du genre bibliothèque
standard ou certains composents de Boost, tu peux être prèsque
sûr que parmi les clients, il y en aura un ou deux, au moins, où
la performance va être importante. Tu seras donc amené à faire
des optimisations (dont inline) sans avoir du feed-back d'un
profiler -- si j'implémentais la bibliothèque standard, par
exemple, std::vector<>::operator[] serait inline, dès le départ.
Mais les gens qui implémentent ce genre de bibliothèque sont
assez rares, et ces arguments ne valent que pour eux.
* Ensuite il y a plusieurs profils de programmeurs: certains
comptent sur le compilateur pour contrer leurs maladresses,
alors que d'autres s'efforcent de programmer à la fois fiable
et efficace. Parmi les seconds, certains y parviennent le plus
souvent et d'autres se trompent.
Ce n'est pas une question de « contrer les maladresses ». C'est
une question de laisser au compilateur faire ce qu'il sait faire
de mieux, et surtout d'investir son effort où il rapporte le
plus.
Il faut dire qu'en quinze ans de C++, en dehors des classes de
bases comme vector et list (ou dans l'époque pré-standard, mon
ArrayOf et DLListOf), je n'ai jamais rencontré un cas où inline
a eu un effet mesurable sur la performance. Au contraire, les
améliorations les plus importantes de la performance ont
toujours été simplifiées du fait qu'on ne mettait rien inline ;
pouvoir modifier l'algorithme et la structure de données d'a en
z sans avoir à récompiler tous les utilisateurs est un avantage
à ne pas negliger.
* Enfin il y a la qualité et "l'intelligence embarquée" du
compilateur: certains sont capables de restructurer
complètement le code, d'autres pas.
Donc AMHA, il n'y a pas de mal à mettre en place un maximum de
précision dans son code, pour autant qu'elle soit réfléchie,
et en sachant que le compilateur peut éventuellement la
remettre en question.
Donc typiquement pour une fonction qui ainsi emballe
simplement une ou deux instructions simples,
... faisant assez peu usage de la pile pour que son coût
d'invocation (en nombre d'instructions) soit important par
rapport au traitement lui-même,
... AMHA la déclaration inline est plutôt une amélioration.
Tu ne prends pas en compte son coût. Le fait qu'il rend tous les
clients dépendants de son implémentation. Dans la plupart des
cas, le coût est bien supérieur À n'importe quel avantage
imaginé.
Mais donc ça nécessite d'avoir une certaine connaissance du
protocole normal d'invocation sur le(s) système(s) visé(s).
C'est donc qu'en plus, ce n'est pas portable. (Je dirais qu'en
général, on écrit du code sans trop savoir sur quelles machines
il risque de tourner. Beaucoup de code que j'ai développé sur
Sparc tourne aujourd'hui sous Linux sur PC ; c'était une
évolution qu'on ne pouvait pas du tout prévoir quand je l'ai
écrit.)
--
James Kanze GABI Software
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 réponds à none" <""(none)"@(none) <""(none)"@(none)">
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ? Par exemple, j'ai une classe avec des membres privés dont je déclare des accesseurs (getFoo, setFoo)
public: int getFoo() const; void setFoo(int value); private: int m_foot;
Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en sachant que ce sont des fonctions au contenu trivial et petit (getFoo se contente de renvoyer m_foot par exemple) ?
Je crois que ça dépend déjà du contexte:
Un peu, certainement.
* Si vous développez une librairie, il peut être intéressant de proposer à votre utilisateur de choisir des fonctions (normalement) plus efficaces sans lui imposer de relire le code. Si vous êtes votre propre utilisateur, vous maîtrisez mieux les usages.
Si tu vends des bibliothèques, tu as effectivement le problème que tu n'as pas la possibilité d'effectuer du profiling sur les applications finales, pour savoir exactement où ça coince. Et si tu vends des bibliothèques de bas niveau, du genre bibliothèque standard ou certains composents de Boost, tu peux être prèsque sûr que parmi les clients, il y en aura un ou deux, au moins, où la performance va être importante. Tu seras donc amené à faire des optimisations (dont inline) sans avoir du feed-back d'un profiler -- si j'implémentais la bibliothèque standard, par exemple, std::vector<>::operator[] serait inline, dès le départ.
Mais les gens qui implémentent ce genre de bibliothèque sont assez rares, et ces arguments ne valent que pour eux.
* Ensuite il y a plusieurs profils de programmeurs: certains comptent sur le compilateur pour contrer leurs maladresses, alors que d'autres s'efforcent de programmer à la fois fiable et efficace. Parmi les seconds, certains y parviennent le plus souvent et d'autres se trompent.
Ce n'est pas une question de « contrer les maladresses ». C'est une question de laisser au compilateur faire ce qu'il sait faire de mieux, et surtout d'investir son effort où il rapporte le plus.
Il faut dire qu'en quinze ans de C++, en dehors des classes de bases comme vector et list (ou dans l'époque pré-standard, mon ArrayOf et DLListOf), je n'ai jamais rencontré un cas où inline a eu un effet mesurable sur la performance. Au contraire, les améliorations les plus importantes de la performance ont toujours été simplifiées du fait qu'on ne mettait rien inline ; pouvoir modifier l'algorithme et la structure de données d'a en z sans avoir à récompiler tous les utilisateurs est un avantage à ne pas negliger.
* Enfin il y a la qualité et "l'intelligence embarquée" du compilateur: certains sont capables de restructurer complètement le code, d'autres pas.
Donc AMHA, il n'y a pas de mal à mettre en place un maximum de précision dans son code, pour autant qu'elle soit réfléchie, et en sachant que le compilateur peut éventuellement la remettre en question.
Donc typiquement pour une fonction qui ainsi emballe simplement une ou deux instructions simples, ... faisant assez peu usage de la pile pour que son coût d'invocation (en nombre d'instructions) soit important par rapport au traitement lui-même, ... AMHA la déclaration inline est plutôt une amélioration.
Tu ne prends pas en compte son coût. Le fait qu'il rend tous les clients dépendants de son implémentation. Dans la plupart des cas, le coût est bien supérieur À n'importe quel avantage imaginé.
Mais donc ça nécessite d'avoir une certaine connaissance du protocole normal d'invocation sur le(s) système(s) visé(s).
C'est donc qu'en plus, ce n'est pas portable. (Je dirais qu'en général, on écrit du code sans trop savoir sur quelles machines il risque de tourner. Beaucoup de code que j'ai développé sur Sparc tourne aujourd'hui sous Linux sur PC ; c'était une évolution qu'on ne pouvait pas du tout prévoir quand je l'ai écrit.)
-- James Kanze GABI Software 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
loufoque
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
Quelles sont les motivations qui peuvent me pousser à utiliser des
méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
kanze
loufoque wrote:
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
-- James Kanze GABI Software 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
loufoque wrote:
Quelles sont les motivations qui peuvent me pousser à
utiliser des méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
Pourquoi ? Dans beaucoup de cas de méta-programmation, la
fonction n'a même pas d'implémentation, puisqu'elle n'est jamais
appelée. (Elle ne sert que dans les sizeof, par exemple.)
--
James Kanze GABI Software
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
Quelles sont les motivations qui peuvent me pousser à utiliser des méthodes inline ?
En méta-programmation par exemple, c'est conseillé.
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
-- James Kanze GABI Software 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
loufoque
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
Pourquoi ? Dans beaucoup de cas de méta-programmation, la
fonction n'a même pas d'implémentation, puisqu'elle n'est jamais
appelée. (Elle ne sert que dans les sizeof, par exemple.)
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
Ceci est un metaprogramme qui genere une serie de fonctions sans argument retournant la valeur de la factorielle de leur argument template. Il ne depend en rien de inline.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
loufoque <loufoque@remove.gmail.com> writes:
Pourquoi ? Dans beaucoup de cas de méta-programmation, la
fonction n'a même pas d'implémentation, puisqu'elle n'est jamais
appelée. (Elle ne sert que dans les sizeof, par exemple.)
Ceci est un metaprogramme qui genere une serie de fonctions sans
argument retournant la valeur de la factorielle de leur argument
template. Il ne depend en rien de inline.
Ce n'est pas un metaprogramme qui retourne la factorielle de
l'argument template: le resultat n'est pas utilisable a la
compilation.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Pourquoi ? Dans beaucoup de cas de méta-programmation, la fonction n'a même pas d'implémentation, puisqu'elle n'est jamais appelée. (Elle ne sert que dans les sizeof, par exemple.)
Ceci est un metaprogramme qui genere une serie de fonctions sans argument retournant la valeur de la factorielle de leur argument template. Il ne depend en rien de inline.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
loufoque
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non. C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non.
C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de
l'argument template: le resultat n'est pas utilisable a la
compilation.
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non. C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Si j'ai faux merci de me signaler la façon correcte de réaliser cela.
Loïc Joly
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non. C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Si j'ai faux merci de me signaler la façon correcte de réaliser cela.
Ce n'est pas faux dans le sens où ça calcule la valeur voulue.
C'est faux dans le sens où ça ne produit pas une constante à la compilation, car il reste des appels de fonctions. On perd donc une grande partie de l'intérêt de la chose.
La manière plus classique est (fautes de frappe à part) :
template <int i> class Fact { enum result {val = Fact<i-1>::val }; }
template<> class Fact<1> { enum result {val = 1}; }
int f() { int tableau[Fact<5>::val]; }
-- Loïc
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non.
C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de
l'argument template: le resultat n'est pas utilisable a la
compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Si j'ai faux merci de me signaler la façon correcte de réaliser cela.
Ce n'est pas faux dans le sens où ça calcule la valeur voulue.
C'est faux dans le sens où ça ne produit pas une constante à la
compilation, car il reste des appels de fonctions. On perd donc une
grande partie de l'intérêt de la chose.
La manière plus classique est (fautes de frappe à part) :
template <int i> class Fact
{
enum result {val = Fact<i-1>::val };
}
template<> class Fact<1>
{
enum result {val = 1};
}
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non. C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Si j'ai faux merci de me signaler la façon correcte de réaliser cela.
Ce n'est pas faux dans le sens où ça calcule la valeur voulue.
C'est faux dans le sens où ça ne produit pas une constante à la compilation, car il reste des appels de fonctions. On perd donc une grande partie de l'intérêt de la chose.
La manière plus classique est (fautes de frappe à part) :
template <int i> class Fact { enum result {val = Fact<i-1>::val }; }
template<> class Fact<1> { enum result {val = 1}; }
int f() { int tableau[Fact<5>::val]; }
-- Loïc
kanze
loufoque wrote:
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non. C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de l'argument template: le resultat n'est pas utilisable a la compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Cela ne remplace pas Factorielle<5>. Il définit Factorielle<5> comme :
(ce qui provoque l'instantiation de Factorielle<4>).
En général, l'inline ne peut pas servir dans la méta-programmation parce qu'il est optionnel. Un compilateur n'est jamais obligé à le faire. Typiquement, d'ailleurs, un compilateur a des limites (parfois assez basses) à la profondeur d'imbrication des fonctions qu'il génère en ligne, ce qui veut dire que pour un i suffisamment grand, Factorielle<i> ne serait pas générée complétement en ligne.
Pour être la méta-programmation, ce genre de manipulation doit se baser sur des « integral constant-expression » définies dans §5.19/1. Quelque chose du genre :
template< unsigned long i > struct Factorielle { static unsigned long const value = i * Factorielle< i - 1 >::value ; operator unsigned long() const { return value ; } } ;
template<> struct Factorielle< 0UL > { static unsigned long const value = 1UL ; operator unsigned long() const { return value ; } } ;
Une expression comme Factorielle<5>() devient donc une invocation du constructeur d'un objet de type Factorielle<5>, qui contient une constante qui vaut 120, et qui se convertit implicitement en un unsigned long avec cette valeur.
(Mais note bien une subtilité dans son utilisation : dans unsigned long const f5a = Factorielle<5>() ; f5a n'est pas une « expression constante ». Pour avoir une expression constante, il faut faire : unsigned long const f5b = Factorielle<5>::value ; Et : #define NULL (Factorielle<5>::value - 120) est une définition légale (mais tordu) de NULL:-).)
-- James Kanze GABI Software 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
loufoque wrote:
Ceci est un metaprogramme qui genere une serie de fonctions
Justement, non.
C'est le but de l'utilisation de inline dans ce cas.
Ce n'est pas un metaprogramme qui retourne la factorielle de
l'argument template: le resultat n'est pas utilisable a la
compilation.
Cela remplace Factorielle<5>() par 1.0*1*2*3*4*5
Cela ne remplace pas Factorielle<5>. Il définit Factorielle<5>
comme :
(ce qui provoque l'instantiation de Factorielle<4>).
En général, l'inline ne peut pas servir dans la
méta-programmation parce qu'il est optionnel. Un compilateur
n'est jamais obligé à le faire. Typiquement, d'ailleurs, un
compilateur a des limites (parfois assez basses) à la profondeur
d'imbrication des fonctions qu'il génère en ligne, ce qui veut
dire que pour un i suffisamment grand, Factorielle<i> ne serait
pas générée complétement en ligne.
Pour être la méta-programmation, ce genre de manipulation doit
se baser sur des « integral constant-expression » définies dans
§5.19/1. Quelque chose du genre :
template< unsigned long i >
struct Factorielle
{
static unsigned long const value
= i * Factorielle< i - 1 >::value ;
operator unsigned long() const
{
return value ;
}
} ;
template<>
struct Factorielle< 0UL >
{
static unsigned long const value = 1UL ;
operator unsigned long() const
{
return value ;
}
} ;
Une expression comme Factorielle<5>() devient donc une
invocation du constructeur d'un objet de type Factorielle<5>,
qui contient une constante qui vaut 120, et qui se convertit
implicitement en un unsigned long avec cette valeur.
(Mais note bien une subtilité dans son utilisation : dans
unsigned long const f5a = Factorielle<5>() ;
f5a n'est pas une « expression constante ». Pour avoir une
expression constante, il faut faire :
unsigned long const f5b = Factorielle<5>::value ;
Et :
#define NULL (Factorielle<5>::value - 120)
est une définition légale (mais tordu) de NULL:-).)
--
James Kanze GABI Software
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
(ce qui provoque l'instantiation de Factorielle<4>).
En général, l'inline ne peut pas servir dans la méta-programmation parce qu'il est optionnel. Un compilateur n'est jamais obligé à le faire. Typiquement, d'ailleurs, un compilateur a des limites (parfois assez basses) à la profondeur d'imbrication des fonctions qu'il génère en ligne, ce qui veut dire que pour un i suffisamment grand, Factorielle<i> ne serait pas générée complétement en ligne.
Pour être la méta-programmation, ce genre de manipulation doit se baser sur des « integral constant-expression » définies dans §5.19/1. Quelque chose du genre :
template< unsigned long i > struct Factorielle { static unsigned long const value = i * Factorielle< i - 1 >::value ; operator unsigned long() const { return value ; } } ;
template<> struct Factorielle< 0UL > { static unsigned long const value = 1UL ; operator unsigned long() const { return value ; } } ;
Une expression comme Factorielle<5>() devient donc une invocation du constructeur d'un objet de type Factorielle<5>, qui contient une constante qui vaut 120, et qui se convertit implicitement en un unsigned long avec cette valeur.
(Mais note bien une subtilité dans son utilisation : dans unsigned long const f5a = Factorielle<5>() ; f5a n'est pas une « expression constante ». Pour avoir une expression constante, il faut faire : unsigned long const f5b = Factorielle<5>::value ; Et : #define NULL (Factorielle<5>::value - 120) est une définition légale (mais tordu) de NULL:-).)
-- James Kanze GABI Software 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