2010-08-08 10 views
19

ich einig Code bin dokumentiere die stark Meta-Programmierung verwendet, zum Beispiel:C++ Meta-Programmierung doxygen Dokumentation

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> { 

was ist ein guter Weg, um solches Konstrukt unter Verwendung von doxygen zu dokumentieren?

+0

Ich denke, Sie müssen richtige Dokumentation schreiben, mit einem Textverarbeitungsprogramm. Wenn ich auf die üblichen doxy-generierten Dokumente (egal wie viele zusätzliche Anmerkungen du hinzufügst) für solche Sachen gestoßen bin, würde ich wahrscheinlich "nein danke" sagen. Aber dann würde ich es wahrscheinlich trotzdem sagen :-) –

+1

Das ist genau, warum ich von der Metaprogrammierung der Vorlage in C++ Abstand halte. Es ist lächerlich. – You

+9

@You gibt es keinen besseren Weg, es zu tun, nicht in irgendeiner Sprache – Anycorn

Antwort

8

Verwenden Sie Präprozessor-Makros. Hier ist ein Beispiel von the not-yet-official Boost.XInt library (derzeit zur Prüfung für die Aufnahme in Boost-Warteschlange):

#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 

Verwenden Sie die #define d Makronamen anstelle der Template-Parameter, überall Sie brauchen sie, wie so:

/*! \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 

und setzen Zeilen wie diese in der 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 

Das Ergebnis ist, dass Doxygen sieht entweder „...“ oder ‚andere‘ für die Template-Parameter und Der Compiler sieht die echten. Wenn Sie die Vorlagenparameter in der Dokumentation für die Klasse selbst beschreiben, muss der Benutzer der Bibliothek sie nur an der Stelle sehen, an der er sie wahrscheinlich suchen wird. Sie werden überall sonst versteckt sein.

Als zusätzlichen Vorteil dieses Entwurfs müssen Sie, wenn Sie Änderungen an den Vorlagenparameterlisten vornehmen müssen, diese nur in den Makrodefinitionen und den Funktionen ändern, die die geänderten Parameter verwenden. Alles andere passt sich automatisch an.

+2

Ich hasse es, zusätzliche Makros/Code nur für Doxygen hinzufügen, als ob das Schreiben der Dokumentation Kommentare nicht genug wäre. Hoffentlich werden sie bald Vorlagen unterstützen. –

+0

Für Bibliothekscode, die Bequemlichkeit, die gesamte Dokumentation auf die Fingerspitzen des Benutzers in einer schön formatierten Weise zu haben, wiegt meine persönliche Unannehmlichkeit der Notwendigkeit, die Makros und den Code hinzuzufügen. YMMV. :-) –

0

Die Meta-Programmierung scheint Mathematik zu implementieren. Ich würde die beschreibenden mathematischen Formeln mit Latex-Escapes in die Doxygen-Dokumentation schreiben.

+0

Hallo. Ich habe mich nicht klar ausgedrückt, ich muss Programmierlogik und nicht mathematische Beschreibung dokumentieren. – Anycorn

+1

@aaa Ich würde sagen, Sie müssen beides dokumentieren. –

+0

@aaa Welche Programmierlogik bleibt das in der Abbildung gezeigte Fragment, wenn Sie es von C++ und Meta-Programmierungstechniken entfernen? –

3

Hier ist mein nehmen auf sie:

/// 
/// \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> {}; 

/// \} 

Vergessen Sie nicht DOXY im PREDEFINED Abschnitt von Doxygen Präprozessor hinzuzufügen.

Ich ziehe es in der Regel Implementierungsdetails vom Benutzer meines Codes zu verstecken, so dass ich ändern, was Doxygen sieht. In diesem Fall finden Sie alle Ihre Spezialisierungen unter einer Gruppe, der Kernel-Gruppe, und unter der Klassenliste werden alle Spezialisierungen gruppiert und haben keinen sehr langen und nicht verständlichen Namen.

Ich hoffe, es hilft.

1

Ich mag es nicht, die Lösung mit zusätzlichen Makros/code, wie the swine.

Hier ist meine Lösung basiert auf einer Nachverarbeitung der HTML-Seiten von Doxygen erzeugt.

Es ist ein Python-Skript, das unter Linux funktioniert. Es unterdrückt alle "< ...>" in Vorlagen-Klassen und Strukturen-Referenzseiten sowie in deren "Liste aller Mitgliederseiten".

Das kleine und weniger invasiv „template < ...>“ vor jeder dokumentierte Methode bleibt.

Führen Sie das Skript mit dem „html /“ Verzeichnis (wo die Dokumentation erstellt wurde) als 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) 
Verwandte Themen