2010-08-08 6 views
19

Je documente un code qui utilise des méta-programmation fortement, par exemple:C++ documentation doxygen méta-programmation

template<rysq::type A, rysq::type B, rysq::type C, rysq::type D, class Transform> 
struct Kernel<meta::braket<A,B,C,D>, Transform, 
       typename boost::enable_if< 
        quadrature<meta::braket<A,B,C,D>, Transform> >::type> 
: Eri <Transform> { 

ce qui est une bonne façon de documenter cette construction en utilisant doxygen?

+0

Je pense que vous devez écrire une documentation appropriée, en utilisant un traitement de texte. Si je suis tombé sur les docs générés par doxy habituels (peu importe combien d'annotation supplémentaire vous ajoutez) pour des trucs comme ça, je pense que je dirais probablement "non merci". Mais alors je le dirais probablement de toute façon :-) –

+1

C'est exactement pourquoi je reste loin de la métaprogrammation de template en C++. C'est ridicule. – You

+9

@Vous n'avez pas de meilleure façon de le faire, pas dans n'importe quelle langue – Anycorn

Répondre

8

Utilisez des macros de préprocesseur. Voici un exemple de the not-yet-official Boost.XInt library (actuellement en attente d'examen pour l'inclusion dans Boost):

#ifdef BOOST_XINT_DOXYGEN_IGNORE 
    // The documentation should see a simplified version of the template 
    // parameters. 
    #define BOOST_XINT_INITIAL_APARAMS ... 
    #define BOOST_XINT_CLASS_APARAMS ... 
    #define BOOST_XINT_CLASS_BPARAMS other 
    #define BOOST_XINT_APARAMS ... 
    #define BOOST_XINT_BPARAMS other 
#else 
    #define BOOST_XINT_INITIAL_APARAMS \ 
     class A0 = parameter::void_, \ 
     class A1 = parameter::void_, \ 
     class A2 = parameter::void_, \ 
     class A3 = parameter::void_, \ 
     class A4 = parameter::void_, \ 
     class A5 = parameter::void_ 
    #define BOOST_XINT_CLASS_APARAMS class A0, class A1, class A2, class A3, \ 
     class A4, class A5 
    #define BOOST_XINT_APARAMS A0, A1, A2, A3, A4, A5 
    #define BOOST_XINT_CLASS_BPARAMS class B0, class B1, class B2, class B3, \ 
     class B4, class B5 
    #define BOOST_XINT_BPARAMS B0, B1, B2, B3, B4, B5 
#endif 

Utilisez les #define d noms de macros au lieu des paramètres du modèle, partout où vous en avez besoin, comme ceci:

/*! \brief The integer_t class template. 

This class implements the standard aribitrary-length %integer type. 

[...lots more documentation omitted...] 
*/ 
template<BOOST_XINT_INITIAL_APARAMS> 
class integer_t: virtual public detail::integer_t_data<BOOST_XINT_APARAMS>, 
    public detail::nan_functions<detail::integer_t_data<BOOST_XINT_APARAMS>:: 
    NothrowType::value, // ...lots more base classes omitted... 
{ 
    // ...etcetera 

et mettre des lignes comme celles-ci dans le Doxyfile:

PREDEFINED    = BOOST_XINT_DOXYGEN_IGNORE 

EXPAND_AS_DEFINED  = BOOST_XINT_INITIAL_APARAMS \ 
         BOOST_XINT_CLASS_APARAMS \ 
         BOOST_XINT_CLASS_BPARAMS \ 
         BOOST_XINT_APARAMS \ 
         BOOST_XINT_BPARAMS 

le résultat est que Doxygen voit soit « ... » ou « autre » pour les paramètres du modèle, et le compilateur voit les vrais. Si vous décrivez les paramètres du modèle dans la documentation pour la classe elle-même, alors l'utilisateur de la bibliothèque n'aura qu'à les voir au même endroit où il est susceptible de les chercher; ils seront cachés partout ailleurs. Comme avantage supplémentaire à cette conception, si vous avez besoin d'apporter des modifications aux listes de paramètres du modèle, il vous suffit de les modifier dans les définitions de macro et les fonctions qui utilisent réellement les paramètres modifiés. Tout le reste s'adaptera automatiquement.

+2

Je déteste ajouter des macros/code supplémentaires pour doxygen, comme si écrire les commentaires de la documentation ne suffirait pas. J'espère qu'ils prendront bientôt en charge les modèles. –

+0

Pour le code de bibliothèque, la commodité d'avoir toute la documentation au bout des doigts de l'utilisateur d'une manière bien formatée l'emporte sur mon inconvénient personnel d'avoir à ajouter les macros et le code. YMMV. :-) –

0

La méta-programmation semble implémenter des maths. J'écrirais les formules mathématiques décrivant avec des évasions de latex dans la documentation de doxygen.

+0

salut. Je ne suis peut-être pas clair, j'ai besoin de documenter la logique de programmation, plutôt que la description mathématique. – Anycorn

+1

@aaa Je dirais que vous devez documenter les deux. –

+0

@aaa Quelle logique de programmation reste le fragment affiché lorsque vous le dépassez des technicités C++ et méta-programmation? –

3

Voici mon avis sur la question:

/// 
/// \defgroup Kernel Kernel 
/// 
/// \brief Kernel does this and that 
/// \{ 

/// \brief Kernel template class brief description. 
template<Braket,Transform,Boolean> 
struct Kernel 
{}; 

/// \brief Kernel partial template specialization brief description. 
/// 
/// More detailed description...<br> 
/// Partially specializes Kernel with meta::braket<A,B,C,D\>.<br> 
/// If quadrature<meta::braket<A,B,C,D\>, Transform\> is true then enable 
/// this algorithm, otherwise enable this other algorithm.<br> 
/// Inherits privately from template class Eri<Transform\><br> 
/// \tparam A   template parameter A of type rysq::type, documentation and concepts 
/// \tparam B   template parameter B of type rysq::type, documentation and concepts 
/// \tparam C   template parameter C of type rysq::type, documentation and concepts 
/// \tparam D   template parameter D of type rysq::type, documentation and concepts 
/// \tparam Transform template parameter class Transform documentation and concepts 
/// \see Kernel\<Braket,Transform,Boolean\> 
/// \see Eri 
/// \see meta::braket 
/// \see quadrature 
#ifdef DOXY 
// This is the documentation version 
template<A,B,C,D,Transform> 
struct Kernel<Braket,Transform,Boolean> 
#else 
// This is what gets compiled 
template<rysq::type A, rysq::type B, rysq::type C, rysq::type D, class Transform> 
struct Kernel<meta::braket<A,B,C,D>, Transform,typename boost::enable_if<quadrature<meta::braket<A,B,C,D>, Transform> >::type> 
#endif 
: Eri <Transform> {}; 

/// \} 

Ne pas oublier d'ajouter DOXY dans la section PREDEFINED de préprocesseur de Doxygen.

Je préfère habituellement cacher les détails de mise en œuvre de l'utilisateur de mon code, donc je changer ce que voit Doxygen. Dans ce cas, vous trouverez toutes vos spécialisations sous un groupe, le groupe Kernel, et sous la liste des classes, toutes les spécialisations seront regroupées et n'auront pas un nom très long et incompréhensible.

Espérons que ça aide.

1

Je n'aime pas la solution avec des macros/code supplémentaire, comme the swine.

Voici ma solution basée sur un post-traitement des pages HTML générées par Doxygen.

Il est un script python qui fonctionne sous Linux. Il supprime toutes les pages "< ...>" dans les Classes de modèles et les Structures de référence, ainsi que dans leur "Liste des pages de tous les membres".

La petite et moins invasive « modèle < ...> » avant chaque méthode documentée reste.

Exécuter le script avec le répertoire "html /" (où la documentation a été générée) comme argument.

#!/usr/bin/python 

import subprocess 
import sys 
import re 

def processFile(fileName): 

    f = open(fileName, 'r') 

    content = f.read(); 

    f.close(); 

    regex = re.compile("(&lt;.*&gt;).*(Template Reference|Member List)") 

    match = re.search(regex, content) 

    if not match: 
    return 

    toRemove = match.group(1) 

    regex = re.compile(toRemove) 

    content = re.sub(regex, "", content) 

    f = open(fileName, 'w') 

    f.write(content) 

    f.close() 


path = sys.argv[1] 

finder = subprocess.Popen(["find", path, "-name", "class*.html", "-o", "-name", "struct*.html"], stdout = subprocess.PIPE) 

(files, junk) = finder.communicate() 

files = files.splitlines() 

print files 

for fname in files: 
    if fname == "": 
continue 
    processFile(fname)