Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2023-03-24T10:15:36+01:00Les derniers messages parus sur le forum de Zeste de Savoir.C++: itérateur générique renvoyé par la fonction membre d'une classe abstraite, message #2496872023-03-24T10:15:36+01:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/16878/c-iterateur-generique-renvoye-par-la-fonction-membre-dune-classe-abstraite/?page=1#p249687<p>Merci beaucoup pour ta réponse ! Je vais tester les différentes options que tu mentionnes et je ferai un retour <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"></p>C++: itérateur générique renvoyé par la fonction membre d'une classe abstraite, message #2496772023-03-23T16:52:23+01:00romantik/@romantikhttps://zestedesavoir.com/forums/sujet/16878/c-iterateur-generique-renvoye-par-la-fonction-membre-dune-classe-abstraite/?page=1#p249677<p>En fait, les itérateurs sont spécifiques à chacun des conteneurs, ils ne suivent pas une hierarchie de type. Les fonctions qui manipulent tout type d’itérateur peuvent le faire parce que ces itérateurs répondent à <a href="https://en.cppreference.com/w/cpp/named_req#Iterator">certaines attentes</a>, on sait comment les manipuler, donc on peut le faire au travers un template. </p>
<p>M’est d’avis que si tu veux interfacer <strong>un conteneur qui a de multiples implémentations</strong>, tu dois aussi interfacer <strong>son itérateur qui aura de multiples implémentations</strong>. Alors je pense que tu devrais faire une classe d’itérateur qui correspond à ton retour de fonction, puis la dériver en deux classes filles qui seront des wrappers aux itérateurs de vector et de ton itérateur perso. </p>
<p>Cette solution me parait la plus adaptée à la question que tu poses, mais j’ai l’impression que de meilleures solutions pourraient exister en remaniant l’architecture pour éviter l’héritage en faisant par exemple de la composition. Mais il faudrait plus d’info, et ça apparait pas aussi évidemment pour moi.</p>
<p><strong>EDIT:</strong> Ou bien selon ce que tu vas faire, tu peux peut-être trouver une solution à base de template, comme par exemple template OptimizationModel pour préciser quel conteneur utiliser. Par contre ScaledModel et EqualityConstraintModel n’hériteront plus de la même chose, est-ce vraiment important ?</p>
<p><strong>EDIT 2 :</strong>
En relisant, je m’apperçois que tu fais une confusion sur l’itérateur. Pour pouvoir appeler <code>get_equality_constraints()</code> dans une for-range loop</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">size_t</span> constraint_index: problem.<span class="hljs-built_in">get_equality_constraints</span>()) {
...
}
</code></pre></div>
<p>Il faut que <code>get_equality_constraints</code> renvoie un conteneur, pas un itérateur. "un conteneur", c’est à dire ? Et bien sur <a href="https://en.cppreference.com/w/cpp/language/range-for">la page du range-for</a> on peut voir qu’il y a plusieurs possibilités : la plus simple est d’avoir une instance de classe qui implémente <code>begin()</code> et <code>end()</code> (qui, eux, renvoient éventuellement l’itérateur, ou dumoins quelque chose qui implémente ++), mais sinon on peut voir qu’il est possible d’avoir juste des implémentations des fonctions libres <code>begin(const CustomType &)</code> et <code>end(const CustomType &)</code>.
Bref, <strong>ton problème en fait n’est pas sur l’itérateur, mais sur le conteneur que ça devrait renvoyer.</strong></p>C++: itérateur générique renvoyé par la fonction membre d'une classe abstraite, message #2496662023-03-22T20:29:00+01:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/16878/c-iterateur-generique-renvoye-par-la-fonction-membre-dune-classe-abstraite/?page=1#p249666<p>Bonsoir,
J’ai un problème de design en C++ et je ne sais pas par quel bout le prendre.<br>
Voici en gros l’idée :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OptimizationModel</span> {</span>
<span class="hljs-keyword">public</span>:
<span class="hljs-function"><span class="hljs-keyword">virtual</span> TypeIterateurSurEntiers <span class="hljs-title">get_equality_constraints</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>= <span class="hljs-number">0</span>;
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScaledModel</span>:</span> <span class="hljs-keyword">public</span> OptimizationModel {
<span class="hljs-keyword">public</span>:
<span class="hljs-function">TypeIterateurSurEntiers <span class="hljs-title">get_equality_constraints</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">override</span></span>;
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EqualityConstrainedModel</span>:</span> <span class="hljs-keyword">public</span> OptimizationModel {
<span class="hljs-keyword">public</span>:
<span class="hljs-function">TypeIterateurSurEntiers <span class="hljs-title">get_equality_constraints</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">override</span></span>;
};
</code></pre></div>
<p>J’ai une classe abstraite qui définit une fonction membre qui sera implémentée par plusieurs sous-classes. Cette fonction retourne un itérateur sur entiers, de telle sorte que je peux l’appeler dans une "range-based for loop" :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">size_t</span> constraint_index: problem.<span class="hljs-built_in">get_equality_constraints</span>()) {
...
}
</code></pre></div>
<p>Suivant la sous-classe (ScaledModel ou EqualityConstrainedModel), j’aimerais pouvoir retourner un itérateur sur un container classique (par exemple std::vector<size_t>) ou bien mon propre type itérable (<a href="https://en.wikipedia.org/wiki/Generator_(computer_programming)#C++">dans ce genre</a>) pour éviter les allocations dynamiques.<br>
Existe-t-il une technique en C++<=17 qui permette de faire cela ?<br>
Merci d’avance, </p>
<p>Charlie</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366372021-08-13T16:22:50+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236637<p>Ca fonctionne, merci <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"><br>
C’est futé, d’exposer le type <code>using matrix_type = MatrixType;</code>.</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366322021-08-13T15:05:42+02:00ads00/@ads00https://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236632<p>D’après les infos que tu donnes, je ferais un truc dans ce style : </p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span><span data-count="18"></span><span data-count="19"></span><span data-count="20"></span><span data-count="21"></span><span data-count="22"></span><span data-count="23"></span><span data-count="24"></span><span data-count="25"></span><span data-count="26"></span><span data-count="27"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span><<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solver</span>, <span class="hljs-title">template</span><</span><span class="hljs-class"><span class="hljs-keyword">class</span>></span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hessian</span>></span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">system</span>
{</span>
Hessian<Solver::matrix_type> hessian_;
Solver solver_;
};
<span class="hljs-keyword">template</span><<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixType</span>></span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">hessianA</span>
{</span>
MatrixType matrix_;
};
<span class="hljs-keyword">template</span><<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixType</span>></span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">basic_solver</span>
{</span>
<span class="hljs-keyword">using</span> matrix_type = MatrixType;
<span class="hljs-function">virutal <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(MatrixType)</span> </span>= <span class="hljs-number">0</span>;
};
<span class="hljs-comment">// concepts si C++20</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">solverA</span> :</span> basic_solver<MatrixA>
{
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(MatrixA)</span> </span>{}
};
<span class="hljs-comment">//</span>
system<MA57Solver, ExactHessian>
</code></pre></div>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366272021-08-13T12:54:06+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236627<p>Cool, ta fonction <code>solve_system()</code> paramétrée par la matrice et le solveur est intéressante.
Par contre, j’ai oublié de préciser un truc : on va résoudre une <strong>séquence</strong> de systèmes linéaires, pas un seul. La méthode <code>InteriorPointMethod::compute_direction()</code> va être appelée plusieurs fois. C’est pour ça que le solveur est un membre de <code>InteriorPointMethod</code>.</p>
<p>Quoi qu’il en soit, ta suggestion est intéressante. Je voulais que la classe abstraite <code>LinearSolver</code> déclare <code>factorize()</code>, mais comme tu l’as montré, chaque sous-classe peut déclarer sa propre <code>factorize(mon_type_de_matrice)</code>. Je vais y réfléchir.</p>
<figure><blockquote>
<p>je me demande aussi si les classes solver ne peuvent pas être réduit à une fonction, car si leur seule responsabilité est de résoudre un système, je crois que ce n’est qu’une séquence d’opération qui s’applique sur les arguments d’entrée, il n’y a pas besoin d’état interne ou je ne sais quoi, si ?</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236626">romantik</a></figcaption></figure>
<p>Mes classes Solver allouent des tableaux et manipulent pas mal de trucs en interne, donc non, elles ne peuvent pas être réduites à une fonction.</p>
<figure><blockquote>
<p>Je rejoins ads00, tu nous expliques comment tu l’as conçu mais pas pourquoi, du coup difficile de faire des choix de design différent<br>
</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236626">romantik</a></figcaption></figure>
<p>Je fais de la recherche dans le domaine des méthodes d’optimisation et je développe un framework qui implémente des composants génériques qu’on peut combiner à la volée. L’idée est d’obtenir automatiquement les combinaisons :</p>
<p>{solveurs MA57, PARDISO} x {stratégies Hessienne} x {interior point, autres méthodes} x {autres trucs}</p>
<p>Si ça vous intéresse (mais ça rentre dans les détails mathématiques), j’ai donné une présentation dans une conf en juillet pour décrire les possibilités du framework : <a href="https://www.researchgate.net/publication/353418272">https://www.researchgate.net/publication/353418272</a></p>
<p>Clairement le projet est ambitieux et je suis un peu limité parfois <img src="/static/smileys/svg/langue.svg" alt=":p" class="smiley"> Mais je suis presque au bout.</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366262021-08-13T12:20:12+02:00romantik/@romantikhttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236626<p>J’ai de plus en plus l’impression que tu essaies de mettre de la généricité là où il n’y en a pas, puisque tu dis toi-même : </p>
<blockquote>
<p><code>LinearSolver<MatrixType></code>, <code>HessianEvaluation<MatrixType></code> et <code>InteriorPointMethod<MatrixType></code> doivent être créés avec le même paramètre de template, ce qui permet de "fixer un unique format de matrice creuse dans tout le code".</p>
</blockquote>
<p>Et je ne fais pas de maths assez pointues pour manipuler ce genre d’objets mathématiques tous les jours, mais je me demande aussi si les classes solver ne peuvent pas être réduit à une fonction, car si leur seule responsabilité est de résoudre un système, je crois que ce n’est qu’une séquence d’opération qui s’applique sur les arguments d’entrée, il n’y a pas besoin d’état interne ou je ne sais quoi, si ?</p>
<p>Je rejoins ads00, tu nous expliques comment tu l’as conçu mais pas pourquoi, du coup difficile de faire des choix de design différent<br>
Et de ce que je comprends SolvA n’est capable de traiter que les matriceA et solvB que les matriceB mais tu veux les rendre generiques parce que tu vas avoir un code en fonction de ta config et tu veux faire</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span></div><pre><code class="hljs language-cpp"><span class="hljs-built_in"><span class="hljs-keyword">switch</span></span>(config)
{
<span class="hljs-keyword">case</span> configA:
MatA mat{...};
SolvA solv{...};
solv.<span class="hljs-built_in">factorize</span>(A);
[...]
<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> configB:
MatB mat{...};
SolvB solv{...};
solv.<span class="hljs-built_in">factorize</span>(mat);
[...] <span class="hljs-comment">// soit exactement le même code que le case configA mais avec des types différents</span>
<span class="hljs-keyword">break</span>;
}
</code></pre></div>
<p>Si c’est ce cas, alors je pense qu’il faut garder les spécificités des classes et faire une fonction générique qui les associe, du style</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span><span data-count="18"></span><span data-count="19"></span><span data-count="20"></span><span data-count="21"></span><span data-count="22"></span><span data-count="23"></span><span data-count="24"></span><span data-count="25"></span><span data-count="26"></span><span data-count="27"></span><span data-count="28"></span><span data-count="29"></span><span data-count="30"></span><span data-count="31"></span><span data-count="32"></span><span data-count="33"></span><span data-count="34"></span><span data-count="35"></span><span data-count="36"></span><span data-count="37"></span><span data-count="38"></span><span data-count="39"></span><span data-count="40"></span><span data-count="41"></span><span data-count="42"></span><span data-count="43"></span><span data-count="44"></span><span data-count="45"></span><span data-count="46"></span><span data-count="47"></span><span data-count="48"></span><span data-count="49"></span><span data-count="50"></span><span data-count="51"></span><span data-count="52"></span><span data-count="53"></span><span data-count="54"></span><span data-count="55"></span><span data-count="56"></span><span data-count="57"></span><span data-count="58"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatA</span>{</span>
[...]
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatB</span>{</span>
[...]
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SolvA</span>{</span>
<span class="hljs-keyword">public</span>:
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatA & mat)</span></span>; <span class="hljs-comment">// n'est capable de traiter que des MatA</span>
[...]
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SolvB</span>{</span>
<span class="hljs-keyword">public</span>:
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatB & mat)</span></span>; <span class="hljs-comment">// n'est capable de traiter que des MatB</span>
[...]
};
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SolvC</span>{</span>
<span class="hljs-keyword">public</span>:
<span class="hljs-comment">// pourquoi pas un solveur qui est capable de traiter les deux</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatA & mat)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatB & mat)</span></span>;
[...]
};
<span class="hljs-function"><span class="hljs-keyword">template</span><class Matrice, class Solveur>
<span class="hljs-keyword">void</span> <span class="hljs-title">solve_system</span><span class="hljs-params">()</span>
</span>{
Matrice mat{...};
Solveur solv{...};
solv.<span class="hljs-built_in">factorize</span>(mat);
[...] <span class="hljs-comment">// le code qu'on avait dans le switch tout à l'heure</span>
}
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">traiter_config</span><span class="hljs-params">(Config config)</span>
</span>{
<span class="hljs-built_in"><span class="hljs-keyword">switch</span></span>(config)
{
<span class="hljs-keyword">case</span> configA:
solve_system<MatA, SolvA>();
<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> configB:
solve_system<MatB, SolvB>();
<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> configC:
solve_system<MatA, SolvC>();
<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> configD:
solve_system<MatB, SolvC>();
<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> configE:
solve_system<MatB, SolvA>(); <span class="hljs-comment">// ======> ERREUR à la compilation</span>
<span class="hljs-keyword">break</span>;
}
</code></pre></div>
<p>EDIT : je n’avais pas lu le dernier message, je comprends ce qui t’as conduit à mettre du template par dessus ton héritage et je pense effectivement que c’était une bonne idée, mais je ne suis pas tout à fait convaincu que l’héritage est utile.</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366242021-08-13T11:32:43+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236624<p>Je lis le choix de solveur et le choix de Hessienne depuis le fichier de config, donc tout se fait à runtime.</p>
<p><code>COOMatrix</code> et <code>CSCMatrix</code> héritent de <code>Matrix</code>.</p>
<p>Les solveurs sont des codes externes (en C ou Fortran) et j’implémente une interface par solveur (<code>MA57LinearSolver</code>, etc.). La classe mère <code>LinearSolver</code> ressemble à ça :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolver</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> SomeMatrixFormat& matrix)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> SomeMatrixFormat& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> </span>= <span class="hljs-number">0</span>;
}
</code></pre></div>
<p>Evidemment, je n’ai pas envie que tous les formats de matrice apparaissent, puisqu’en pratique, un solveur ne travaille que sur un format. Donc pour éviter ça :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolver</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> COOMatrix& matrix)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> CSCMatrix& matrix)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> COOMatrix& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> CSCMatrix& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> </span>= <span class="hljs-number">0</span>;
}
</code></pre></div>
<p>ou des signatures sur la classe mère (ce qui oblige à faire des casts dans les méthodes) :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolver</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> Matrix& matrix)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> Matrix& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> </span>= <span class="hljs-number">0</span>;
}
</code></pre></div>
<p>je template la classe :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixFormat</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolver</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatrixFormat& matrix)</span> </span>= <span class="hljs-number">0</span>;
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatrixFormat& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> </span>= <span class="hljs-number">0</span>;
}
</code></pre></div>
<p>Mes classes <code>MA57Solver</code> et <code>PardisoSolver</code> héritent de <code>LinearSolver</code> et spécialisent le paramètre du template avec le format de matrice qu’ils utilisent :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MA57Solver</span>:</span> <span class="hljs-keyword">public</span> LinearSolver<COOMatrix>
</code></pre></div>
<p>ce qui me permet de définir les méthodes <code>factorize</code> et <code>solve</code> directement sur le bon format de matrice :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span></div><pre><code class="hljs language-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MA57Solver</span>:</span> <span class="hljs-keyword">public</span> LinearSolver<COOMatrix> {
<span class="hljs-comment">// allocation de trucs, appels à Fortran</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> COOMatrix& matrix)</span> <span class="hljs-keyword">override</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">solve</span><span class="hljs-params">(<span class="hljs-keyword">const</span> COOMatrix& matrix, <span class="hljs-keyword">const</span> std::vector<<span class="hljs-keyword">double</span>>& rhs)</span> <span class="hljs-keyword">override</span></span>;
}
</code></pre></div>
<p>Idem pour <code>HessianEvaluation</code> : j’ai une classe mère abstraite, et autant de classes filles que de stratégies (exact, convexifiée, quasi-Newton). Cette classe stocke une Hessienne (une matrice creuse) qu’elle évalue et stocke directement dans le bon format. Donc j’ai templaté la classe mère et les classes filles :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixFormat</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HessianEvaluation</span> {</span>
MatrixFormat hessian;
}
<span class="hljs-keyword">template</span> <<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixFormat</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExactHessianEvaluation</span> :</span> <span class="hljs-keyword">public</span> HessianEvaluation<MatrixFormat> {
...
}
...
</code></pre></div>
<p>Ma classe <code>InteriorPointMethod</code> contient des <code>unique_ptr</code> vers le <code>LinearSolver</code> et la <code>HessianEvaluation</code>, donc je continue de templater :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span><span data-count="18"></span><span data-count="19"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixFormat</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InteriorPointMethod</span> {</span>
<span class="hljs-keyword">public</span>:
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">compute_direction</span><span class="hljs-params">(...)</span> </span>{
<span class="hljs-comment">// evaluate the Hessian at the current point</span>
<span class="hljs-keyword">this</span>->hessian_evaluation-><span class="hljs-built_in">evaluate_hessian</span>(...);
<span class="hljs-comment">// form the linear system around this->hessian_evaluation.get_hessian()</span>
MatrixFormat linear_system = ...
<span class="hljs-comment">// compute symbolic factorization of the linear system</span>
<span class="hljs-keyword">this</span>->linear_solver-><span class="hljs-built_in">factorize</span>(linear_system);
...
}
<span class="hljs-keyword">private</span>:
std::unique_ptr<LinearSolver<MatrixFormat> > linear_solver;
std::unique_ptr<HessianEvaluation<MatrixFormat> > hessian_evaluation;
}
</code></pre></div>
<p>Au niveau des combinaisons possibles : <code>InteriorPointMethod</code> doit pouvoir tourner sur le produit cartésiens des stratégies :<br>
<strong>MA57 + Hessienne exacte, MA57 + Hessienne convexifiée, MA57 + Hessienne quasi-Newton</strong> (tout dans le format COO)<br>
<strong>Pardiso + Hessienne exacte, Pardiso + Hessienne convexifiée, Pardiso + Hessienne quasi-Newton</strong> (tout dans le format CSC). </p>
<p>Je suis conscient que c’est bizarre de tout templater alors que tout se fait au runtime <img src="/static/smileys/svg/rire.svg" alt=":lol:" class="smiley"> Ceci dit, si le paramètre du template a 2 valeurs possibles, ça se gère très bien à la volée dans une factory.</p>
<p>J’espère que le design est plus clair <img src="/static/smileys/svg/clin.svg" alt=";)" class="smiley"></p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366232021-08-13T10:50:50+02:00ads00/@ads00https://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236623<p>Ca ne répond toujours pas aux questions <img src="/static/smileys/svg/langue.svg" alt=":p" class="smiley"></p>
<p>Il faudrait commencer par savoir ce que tu fais runtime et compile time, pourquoi tu as besoin d’avoir des objets pour tes solvers, quel est le code commun etc .. Tu dis que t’as un héritage pour tes solvers, mais qu’ils sont externes. On peut choisir entre 3 types de HessianEvaluation, mais tu mets un paramètre template lié au format de matrice.</p>
<p>Si tu fais une classe template mais que tu spécialises tous les types, autant faire des surcharges ou des classes nommées.</p>
<p>Ecris d’abord l’interface que tu veux pour différents cas, et ensuite tu fais ton design à partir de la. La tu pars du principe que tu veux X qui hérite de Y, et Z qui est templaté, mais on ne sait pas pourquoi.</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2366212021-08-13T10:04:13+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236621<p>Merci pour vos réponses ! J’essaie effectivement de faire un truc compliqué, je vais récapituler ce qu’il se passe dans mon framework : en gros, </p>
<ul>
<li>j’ai une classe <code>InteriorPointMethod</code> qui résout des systèmes linéaires ;</li>
<li>le système linéaire est formé autour de la Hessienne du problème (matrice des dérivées secondes) au point courant. Il est représenté sous forme de matrice creuse ;</li>
<li>la Hessienne est évaluée par un membre de <code>InteriorPointMethod</code> de type <code>HessianEvaluation</code>. On peut choisir entre Hessienne exact, convexifiée et quasi-Newton ;</li>
<li>il existe plusieurs formats pour représenter des matrices creuses. J’en ai (au moins) deux (<a href="https://en.wikipedia.org/wiki/Sparse_matrix#Coordinate_list_(COO)">COO</a> et <a href="https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_column_(CSC_or_CCS)">CSC/R</a>) ;</li>
<li>le système linéaire est résolu par des codes (solveurs) externes (par exemple <a href="https://www.hsl.rl.ac.uk/catalogue/ma57.html">MA57</a> ou <a href="https://www.pardiso-project.org/">PARDISO</a>) pour lesquels j’ai écrit des interfaces <code>MA57Solver</code> et <code>PardisoSolver</code> qui héritent de <code>LinearSolver</code> ;</li>
<li>ces solveurs linéaires travaillent chacun avec un seul format de matrice creuse : COO pour MA57 et CSC/R pour PARDISO ;</li>
<li>le choix d’un solveur linéaire (MA57 ou PARDISO) détermine donc le format de matrice creuse qui va être utilisé dans la séquence suivante : évaluation de la Hessienne, formation du système linéaire, résolution du système linéaire par le solveur linéaire ;</li>
<li>le solveur linéaire est choisi à l’exécution lorsque le fichier de configuration du framework est lu.</li>
</ul>
<p>J’ai donc templaté :</p>
<ul>
<li>ma classe <code>LinearSolver</code> afin de spécifier quel format de matrice le solveur peut résoudre (cf premier code du premier message) ;</li>
<li>la classe <code>HessianEvaluation</code> qui crée la matrice Hessienne directement dans le bon format creux ;</li>
<li>la classe <code>InteriorPointMethod</code> qui contient comme membres une instance de <code>LinearSolver</code> et une instance de <code>HessianEvaluation</code>.</li>
</ul>
<p><code>LinearSolver<MatrixType></code>, <code>HessianEvaluation<MatrixType></code> et <code>InteriorPointMethod<MatrixType></code> doivent être créés avec le même paramètre de template, ce qui permet de "fixer un unique format de matrice creuse dans tout le code".
J’ai donc dû templater mes factories (cf deuxième code du premier message) puisque les 3 classes <code>LinearSolver</code>, <code>HessianEvaluation</code> et <code>InteriorPointMethod</code> sont templatées. Je me retrouve donc avec ce drôle de code.</p>
<p>Ca vous inspire un autre design ?</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2365952021-08-12T15:28:22+02:00ads00/@ads00https://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236595<p>Pour ton design, il faudrait que tu donnes plus d’infos, pourquoi tu veux utiliser de l’héritage, pourquoi tu as besoin d’un objet solver ? etc ..</p>
<p>Tu pourrais très bien avoir <code>linear_solver::machin(A)</code> et <code>linear_solver::truc(B)</code></p>
<p>Ça veut dire quoi "fixer le type des matrices" à l’exécution ?</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2365832021-08-12T11:26:22+02:00romantik/@romantikhttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236583<p>Salut,<br>
Tu te fais des noeuds au cerveau, tu mélanges 2 approches pour résoudre le même problème de généricité.<br>
Tu n’as pas besoin du template pour redéfinir une méthode virtuelle, ou tu n’as pas besoin d’un héritage pour spécialiser ton template. </p>
<p>Quant aux unique_ptr qui ne comprennent pas l’affectation d’un unique_ptr d’une classe dérivée … c’est un peu dommage que ça ne marche pas, mais effectivement, à cause du template ce sont deux types distincts et donc ce n’est pas possible. En revanche il est possible de construire un "unique_ptr<Base>" autour d’un pointeur "Derive*"</p>[C++] Factory d'une classe qui spécialise une classe mère template, message #2365802021-08-12T11:01:33+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236580<p>Voilà la solution que j’ai reçue sur StackOverflow : il faut spécialiser la factory.</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> MatrixType>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Factory</span>;</span>
<span class="hljs-keyword">template</span> <>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Factory</span><</span>MatrixTypeA> {
std::unique_ptr<LinearSolver<MatrixTypeA> > <span class="hljs-built_in">create</span>(<span class="hljs-keyword">const</span> std::string& name) {
<span class="hljs-comment">// select a LinearSolve<MatrixTypeA> and return it</span>
}
};
<span class="hljs-keyword">template</span> <>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Factory</span><</span>MatrixTypeB> {
std::unique_ptr<LinearSolver<MatrixTypeB> > <span class="hljs-built_in">create</span>(<span class="hljs-keyword">const</span> std::string& name) {
<span class="hljs-comment">// select a LinearSolver<MatrixTypeB> and return it</span>
}
};
</code></pre></div>[C++] Factory d'une classe qui spécialise une classe mère template, message #2365702021-08-12T01:12:22+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15589/c-factory-dune-classe-qui-specialise-une-classe-mere-template/?page=1#p236570<p>Salut,<br>
je développe un framework C++ pour l’optimisation mathématique et je m’arrache un peu les cheveux pour trouver un design qui tient la route au niveau des matrices creuses.</p>
<p>En gros :</p>
<ul>
<li>j’ai deux types de représentations de matrices creuses : appelons les <code>A</code> et <code>B</code> ;</li>
<li>j’ai deux solveurs linéaires, <code>machin</code> et <code>truc</code>. <code>machin</code> travaille exclusivement avec des matrices de type <code>A</code> et <code>truc</code> exclusivement avec des matrices de type <code>B</code>.</li>
<li>du coup, j’aimerais templater mon code pour que le choix d’un solveur <code>machin</code> ou <code>truc</code> (à l’exécution) fixe le type des toutes les matrices (<code>A</code> ou <code>B</code>) dans tout le reste du code.</li>
</ul>
<p>J’ai essayé le code (simplifié) suivant :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixType</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolver</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatrixType& matrix)</span> </span>= <span class="hljs-number">0</span>;
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolverMachin</span>:</span> <span class="hljs-keyword">public</span> LinearSolver<MatrixTypeA> {
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatrixTypeA& matrix)</span> <span class="hljs-keyword">override</span></span>;
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolverTruc</span>:</span> <span class="hljs-keyword">public</span> LinearSolver<MatrixTypeB> {
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">factorize</span><span class="hljs-params">(<span class="hljs-keyword">const</span> MatrixTypeB& matrix)</span> <span class="hljs-keyword">override</span></span>;
}
</code></pre></div>
<p>Le supertype commun à <code>LinearSolverMachin</code> et <code>LinearSolverTruc</code> étant le type template <code>LinearSolver</code>, j’ai templaté la classe <code>LinearSolverFactory</code> elle-même :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span><<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MatrixType</span>></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinearSolverFactory</span> {</span>
<span class="hljs-keyword">public</span>:
std::unique_ptr<LinearSolver<MatrixType> > <span class="hljs-built_in">create</span>(<span class="hljs-keyword">const</span> std::string& solver_name) {
<span class="hljs-keyword">if</span> (solver_name == <span class="hljs-string">"machin"</span>) {
<span class="hljs-keyword">return</span> std::make_unique<LinearSolverMachin>();
}
<span class="hljs-keyword">else</span> {
<span class="hljs-keyword">return</span> std::make_unique<LinearSolverTruc>();
}
}
</code></pre></div>
<p>Puis à plus haut niveau, j’appelle <code>LinearSolverFactory::create()</code> avec le bon nom de solveur et le bon paramètre de template.</p>
<p>Malheureusement le code ne compile pas (il me dit que le <code>std::unique_ptr<LinearSolverMachin></code> ne peut pas être converti en <code>std::unique_ptr<LinearSolver<MatrixTypeA> ></code>). Je ne suis pas assez calé en templates pour voir si le problème peut être corrigé. </p>
<p>Merci d’avance pour votre aide <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"></p>
<p>Charlie</p>Classe abstraite, paramètre abstrait et héritage, message #2347012021-05-28T12:59:53+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15384/classe-abstraite-parametre-abstrait-et-heritage/?page=1#p234701<p>Merci !<br>
Je pense que que le type <code>V</code> est connu à la compilation. Cependant, <code>DistributedVector</code> (je crois que cette classe a été ajoutée par les premiers développeurs de notre code) est une structure arborescente dont les membres sont eux-mêmes des <code>Vector</code>, dont les types ne sont connus qu’à l’exécution… et là c’est le drame.</p>
<p>Je vais en discuter avec mon collègue <img src="/static/smileys/svg/clin.svg" alt=";)" class="smiley"> On va jeter un oeil à Eigen également.</p>Classe abstraite, paramètre abstrait et héritage, message #2346772021-05-28T00:20:10+02:00lmghs/@lmghshttps://zestedesavoir.com/forums/sujet/15384/classe-abstraite-parametre-abstrait-et-heritage/?page=1#p234677<p>Votre code. Savez-vous quel type de vecteur il est censé utiliser à un instant T? Si oui, utilisez ce type là. Si vous arrivez à bannir l’emploi du supertype, bingo vous pourrez virer ce pseudo polymorphisme non LSPien à mon goût (vu qu’il refuse la mixité)</p>
<p>Et pour les appels sans cast, il faut libérer les fonctions. ie.</p>
<div class="hljs-code-div hljs-code-c++"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span></div><pre><code class="hljs language-c++"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">votre_code</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">using</span> V = SimpleVector ; <span class="hljs-comment">// à supposer que cela soit possible</span>
V v1 = ...
V v2 = ...
<span class="hljs-keyword">auto</span> ps = dot(v1, v2); <span class="hljs-comment">// libération de la fonction: elle n'est plus membre</span>
</code></pre></div>
<p>Ce que je propose c’est qu’au lieu d’avoir <code>SimpleVector::dot(ParentVector cont&) const</code> qui caste le paramètre en <code>SimpleVector</code> et même chose pour les distribués, il n’y a maintenant plus qu’une fonction qui prend 2 <code>SimpleVector</code>, et une autre pour les distribués (d’ailleurs il sort d’où cet autre enfant?). </p>
<p>Mais ceci ne sera possible que si votre code manipule explicitement un type enfant ou l’autre à la compilation. Si le type exact de vecteur ne peut être déterminé qu’à l’exécution, c’est cuit! On en revient à un besoin de double dispatch (qui écarte la mixité — bouhhh!). On peut le résoudre avec un downcasting (mais qu’est-ce que ce code ressemble à l’implémentation de equals du monde Java!…), ou avec des visiteurs.</p>
<p>Quitte à tout casser, migrer à eigen n’est vraiment pas possible?</p>Classe abstraite, paramètre abstrait et héritage, message #2346762021-05-27T23:50:48+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15384/classe-abstraite-parametre-abstrait-et-heritage/?page=1#p234676<p>Merci pour ta réponse.</p>
<p>Effectivement, on a la main sur le code et on ne s’est pas gênés pour le triturer et en virer une bonne partie. La bibli est typique d’un code d’il y a 20 ans et je m’en passerais bien.</p>
<p>La classe <code>Vector</code> (et ses sous-classes) est utilisée intensivement dans notre code, mais je suis prêt à développer une nouvelle version si celle-ci est plus simple à maintenir. J’ai effectivement pensé à une alternative qui consiste à paramétriser les classes appelantes par un sous-type <code>V</code> de <code>Vector</code> (donc <code>SimpleVector</code> ou <code>DistributedVector</code>) afin de forcer le même type pour tous les vecteurs :</p>
<div class="hljs-code-div hljs-code-cpp"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span></div><pre><code class="hljs language-cpp"><span class="hljs-keyword">template</span> <type V>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NomClasseAppelante</span> {</span>
<span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">methode</span><span class="hljs-params">()</span> </span>{
V vector1 = ...
V vector2 = ...
<span class="hljs-keyword">double</span> v1_dot_v2 = vector1.dot(vector2);
...
}
}
</code></pre></div>
<p>puis d’instantier <code>V</code> à <code>SimpleVector</code> ou <code>DistributedVector</code>. C’est à cette méthode que tu pensais ?</p>
<p>Mon collègue/co-développeur approuve globalement la méthode mais a peur qu’il faille paramétrer beaucoup de nos classes. A voir…</p>
<p>Quant à la pertinence des sous-types substituables : bonne question. L’idée dans notre code est de pouvoir switcher entre 3 modes : calcul séquentiel, calcul parallèle et calcul distribué. Pour chaque mode, on a une sous-classe de <code>Vector</code> qui travaille avec une certaine représentation. L’avantage de la classe abstraite <code>Vector</code> est que les classes appelantes n’ont pas besoin de savoir dans quel mode on se trouve. Mais comme on l’a vu plus haut, on doit pouvoir régler ça via polymorphisme paramétrique.</p>Classe abstraite, paramètre abstrait et héritage, message #2346752021-05-27T22:03:24+02:00lmghs/@lmghshttps://zestedesavoir.com/forums/sujet/15384/classe-abstraite-parametre-abstrait-et-heritage/?page=1#p234675<p>La première idée qui me vient est de demander s’il y a une raison d’utiliser une lib qui n’a pas bougé en 7 ans et qui n’est pas une des célébrités du domaine (eigen, blaze, armadillo).</p>
<p>L’abus d’objets de la sorte (et de divers antipatterns que je vois comme mélanger fabs avec des doubles) me laisse un sentiment de chercheur non spécialiste du calcul HPC et qui découvre le C++ tandis qu’il transpose ses connaissances du Java et travaille en parallèle sur sa thèse. J’imagine que la lib a le calcul dont vous avez absolument besoin et qui ne se trouve pas ailleurs?</p>
<p>Il y a quelque chose que je ne comprends pas. Comment veux-tu te passer des casts alors qu’ils engrainés dans la bibliothèque, ou encore virer des fonctions? Tu as la main sur la lib pour la modifier?</p>
<p>Il faut libérer les fonctions pour moi vu ce coté: en vrai on ne mélange pas. Donc j’irai même plus loin si on ne mélange pas, est-ce vraiment des sous-types substituables que l’on voulait écrire? Mais es-tu prêt pour porter une révolution de dés-OO-fication de la lib pour passer au polymorphisme paramétrique?</p>Classe abstraite, paramètre abstrait et héritage, message #2346722021-05-27T18:05:01+02:00cvanaret/@cvanarethttps://zestedesavoir.com/forums/sujet/15384/classe-abstraite-parametre-abstrait-et-heritage/?page=1#p234672<p>Salut,</p>
<p>J’ai rejoint un projet de recherche qui utilise OOQP, en particulier sa classe <a href="https://github.com/emgertz/OOQP/blob/master/src/Vector/OoqpVector.h">OoqpVector</a>. C’est une classe abstraite avec un certain nombre de méthodes virtuelles, par exemple :</p>
<p><code>virtual double dotProductWith(OoqpVector& v) = 0</code></p>
<p>Cette méthod est implémentée par deux sous-classes <code>SimpleVector</code> et <code>DistributedVector</code>. En raison de la généricité, <code>OoqpVector::dotProductWith</code> autorise toutes les combinaisons possibles :</p>
<ul>
<li><code>SimpleVector.dotProductWith(SimpleVector)</code></li>
<li><code>DistributedVector.dotProductWith(DistributedVector)</code></li>
<li><code>SimpleVector.dotProductWith(DistributedVector)</code></li>
<li><code>DistributedVector.dotProductWith(SimpleVector)</code></li>
</ul>
<p>Par contre, en pratique, la méthode est toujours appelée sur 2 vecteurs de même type (combinaisons 1 et 2). Les auteurs de OOQP ont donc implémenté <code>SimpleVector::dotProductWith(OoqpVector&)</code> et <code>DistributedVector::dotProductWith(OoqpVector&)</code> en <strong>castant</strong> le paramètre vers le type courant (<code>Simple</code> ou <code>Distributed</code>).</p>
<p>Ca fonctionne sans problème, mais je trouve ça assez vilain et je me demande s’il est possible de se passer des casts.</p>
<p>Une possibilité serait de virer <code>OoqpVector::dotProductWith</code>, de déclarer les méthodes spécialisées <code>SimpleVector::dotProductWith(SimpleVector&)</code> et <code>DistributedVector::dotProductWith(DistributedVector&)</code>, et d’imposer aux classes/méthodes appelantes à forcer le même type pour les 2 vecteurs. Cela dit, le code utilise pas mal de <code>OoqpVectors</code> (abstraits) un peu partout, donc ça m’a l’air compliqué.</p>
<p>Auriez-vous des idées ?<br>
Merci,</p>
<p>Charlie</p>question POO : "double héritage", message #2276272020-11-03T10:34:09+01:00Ksass`Peuk/@Ksass%60Peukhttps://zestedesavoir.com/forums/sujet/14683/question-poo-double-heritage/?page=1#p227627<p>Ok, donc ton problème vient quelque part du fait que c’est précisément pas une bonne manière d’utiliser de l’héritage ici <img src="/static/smileys/svg/clin.svg" alt=";)" class="smiley"> .</p>
<p>L’important dans une classe c’est les fonctions qu’elle propose, pas les données qu’elle contient (qui sont secondaires et juste un moyen de fournir les fonctionnalités). Tel que tu présentes ton code, ce qu’on se dit immédiatement c’est : l’héritage au niveau des Personne n’est pas utile puisqu’il n’y a pas de différence de service rendu (puisqu’il n’y a pas de service).</p>question POO : "double héritage", message #2276252020-11-03T10:28:11+01:00Michelouzooo/@Michelouzooohttps://zestedesavoir.com/forums/sujet/14683/question-poo-double-heritage/?page=1#p227625<p>Mon idée au départ était plus une curiosité qu’une volonté de faire quelque chose de concret mais voici un exemple (pas forcément pertinent et limite caricatural)</p>
<p><img src="https://nsa40.casimages.com/img/2020/11/03/201103102115539843.png"></p>
<p>Je souhaite que chaque sous-classe de Personne possède un attribut "hobby", ce qui m’amène à définir hobby dans la classe mère. </p>
<p>Mais ce n’est pas suffisant, car je souhaite aussi qu’il y ait une sorte de couplage entre les attributs des sous-classes de Personne et celles de Hobby. Autrement dit, qu’une personne Jeune ne peut avoir qu’un hobby de type Sport, une personne Retraitée un hobby JeuDeCartes. Ce pourquoi j’ai précisé cela dans les sous-classes. Et la question était de savoir si l’on pouvait redéfinir ces attributs de cette façon, dans les classes héritées.</p>
<p>Plus j’avance et plus je me dis que ce double héritage n’est peut-être pas le schéma idéal</p>
<p>J’espère avoir été plus clair par cet exemple. </p>
<figure><blockquote>
<p>Pour ça, tu n’as pas d’autre choix que d’avoir un pointeur (intelligent) ou une référence dans ton type de base, sinon tu ne pourrais pas avoir de polymorphisme sur cette variable.</p>
<p></p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/14683/question-poo-double-heritage/?page=1#p227619">Ksass`Peuk</a></figcaption></figure>
<p>Je vais essayer d’explorer cette idée, merci</p>