C++ meta-programming doxygen documentation

后端 未结 4 1039
深忆病人
深忆病人 2020-12-05 10:55

I am documenting some code which uses meta-programming heavily, for example:

 template

        
相关标签:
4条回答
  • 2020-12-05 11:23

    I don't like the solution with additional macros/code, like the swine.

    Here is my solution based on a post-processing of the HTML pages generated by Doxygen.

    It is a python script which works under Linux. It suppresses all the "<...>" in Template Classes and Structures Reference pages, and also in their "List of all members pages".

    The little and less invasive "template<...>" before each documented method remains.

    Run the script with the "html/" directory (where the documentation was generated) as 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)
    
    0 讨论(0)
  • 2020-12-05 11:31

    Use preprocessor macros. Here's an example from the not-yet-official Boost.XInt library (presently queued for review for inclusion in 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
    

    Use the #defined macro names instead of the template parameters, everywhere you need them, like 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
    

    And put lines like these in the 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
    

    The result is that Doxygen sees either "..." or "other" for the template parameters, and the compiler sees the real ones. If you describe the template parameters in the documentation for the class itself, then the user of the library will only need to see them in the one place that he's likely to look for them; they'll be hidden everywhere else.

    As an additional advantage to this design, if you ever need to make changes to the template parameter lists, you only need to change them in the macro definitions and the functions that actually use the changed parameters. Everything else will adapt automatically.

    0 讨论(0)
  • 2020-12-05 11:37

    The meta-programming seems to implement maths. I would write the describing mathematical formulas with latex escapes in the doxygen documentation.

    0 讨论(0)
  • 2020-12-05 11:38

    Here is my take on it:

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

    Don't forget to add DOXY in the PREDEFINED section of Doxygen's preprocessor.

    I usually prefer to hide implementation details from the user of my code, so I change what Doxygen sees. In this case, you will find all your specializations under one group, the Kernel group, and under the class list, all specializations will be grouped together and won't have a very long and un-comprehensible name.

    Hope it helps.

    0 讨论(0)
提交回复
热议问题