如何使用doxygen记录C++模板和模板元函数?

73

在Doxygen中,有关C++模板和模板元函数的文档应该遵循哪些指南?

例如:

/// @brief metafunction for generation of a map of message types to
/// their associated callbacks.
/// @tparam Seq the list of message types
template< class Seq >
struct generate_callback_map
{
    typedef typename mpl::transform< Seq
                                   , build_type_signature_pair< mpl::_1 > 
                                   >::type vector_pair_type;
    typedef typename fusion::result_of::as_map< vector_pair_type >::type type;
};

目前我已经看到以下建议:

  • @tparam 用于描述模板参数。
  • @arg 另一种描述模板参数的方式。
  • @brief 用于描述元函数。

如何记录元函数的“返回类型”?

有没有人对在C++模板中使用Doxygen有好的建议或个人偏好?


4
@Pubby:那真是个非常有用的建议。那你会用什么呢? - Jan Hudec
@JanHudec 请自己编写代码而不是生成代码。当然要使用样式指南和一致的格式。可读性强的代码对于TMP来说非常重要,因为它们是有缺陷的抽象层。使用伪代码进行解释会有所帮助,因为C++语法很糟糕。 - Pubby
5
@Pubby一定是在开玩笑。好的文档是不需要查看代码的。你只需要阅读头文件中的解释注释,甚至不需要查看实现,也就是说,你不需要关心代码风格、格式、可读性等等——这才是好的文档。 Doxygen 只是从源代码中(理想情况下是从头文件中)提取这些文档的工具。当然,如果你想像一堆“targzipped”头文件那样分发API描述,而不是html / pdf /任何其他格式,那么祝你好运;我更喜欢使用 Doxygen - Hi-Angel
2个回答

71

使用@tparam表示模板参数,@arg表示函数参数。对于返回值,请使用@return。这里没有返回值,只有typedef

顺便说一下,您的示例代码看起来不像元函数。元函数是利用SFINAE执行C++最初未预期执行的操作(例如反射)的复杂函数。您的generate_callback_map只是C++03中的模板typedef替代品。

您缺少的是typedef的文档和如何使用此模板的文档。

/// @brief metafunction for generation of a map of message types to
/// their associated callbacks.
/// @details
/// Usage: Use <tt>generate_callback_map<Type>::type</tt> to ...
/// @tparam Seq the list of message types
/// 
template< class Seq >
struct generate_callback_map
{
  /// @brief It's a good idea to document all of your typedefs.
  typedef typename mpl::transform< Seq
                                 , build_type_signature_pair< mpl::_1 > 
                                 >::type vector_pair_type;

  /// @brief This is why generate_callback_map exists. Document it!
  typedef typename fusion::result_of::as_map< vector_pair_type >::type type;
};

10
在C++中,“元函数”通常指像OP所示的代码。是的,它是一个typedef,但该typedef包含了评估编译时指定的“函数”所得出的类型。 - jalf
7
我认为这里是有返回值的。正式地说,类没有返回值,但从逻辑上讲,type typedef 是一种返回值。最好将其作为类的主要文档体而不是单独成员进行记录。 - Jan Hudec
2
有人可能会争辩说,在这里存在一个返回值,就像这个结构体定义是一个函数一样。但从Doxygen和相关/兼容的文档生成器的角度来看,尝试在示例中标记任何内容为@return只会让它变得混乱。@david的typedef文档服务于此功能并且是明确无歧的,但可以通过对结构体本身进行简要说明来增强其功能。 - Ionoclast Brigham
1
这实际上应该被选择为正确答案。 - Sergei Krivonos
文档链接:https://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdtparam - Volodymyr
3
Doxygen文档中tparam的最新链接:http://www.doxygen.nl/manual/commands.html#cmdtparam - Justin Time - Reinstate Monica

25

我认为使用文档高级模板结构与doxygen不可能,因为它最初是为面向对象范例而设计的,而不是元编程。例如,GNU STL (libstdc++) 使用了doxygen,但在STL中对元编程的文档化做得不够好

另一方面,boost使用了自己的工具:QuickBook使用单独的文本文件和doxygen记录的源代码来生成BoostBook标记(DocBook扩展),进而生成html/pdf。 结果比libstdc++更有信息量,但显然需要开发人员投入更多工作。

由于boost文档在元编程方面被认为是最好的之一,您可以选择这条路线,特别是它可以补充doxygen-您可以重复使用现有的标记。

虽然它并没有完全回答你的问题,但你可能会对最近的clang developments感兴趣。当使用--with-extra-options=-Wdocumentation构建clang时,它会在语义上检查你的doxygen标记和代码,并生成文档警告。这样强制你保持文档/代码同步。

1
我同意,大部分的boost文档都非常好,遵循他们的方法肯定是有道理的。 - mark
2
这里有非常好的信息。Clang/LLVM文档检查的链接非常有用!我只需要使用-Wdocumentation就可以让它工作了。虽然它并没有严格回答OP的问题。 - Ionoclast Brigham
2
关于“例如,GNU STL(libstdc ++)使用doxygen,但在STL的元编程文档方面做得很差。” GNU整体上文档不好。看看源代码,现有的少量注释最多也是很差。用GNU糟糕的注释作为doxygen失败的例子是不公平的。一个更好的例子将是一些有良好注释的源代码,在doxygen中看起来仍然很糟糕。 - David Hammen
@DavidHammen确实,这个例子并不是最好的,但我很难找到更好的例子:在doxygen中有良好文档记录的库往往缺乏模板,而以模板为主的库则往往使用其他东西而非doxygen。欢迎提供建议! - Antoine
4
@Antoine - Eigen 是一个 heavily templated 的库。他们的 API 是由 doxygen 自动产生的。但是,它们的 API 文档能够独立存在吗?当然不行。对于足够复杂的软件包来说,仅靠 API 是远远不够的。就像 C++ 标准库一样,需要多本书来描述该库。以下是 Eigen 源代码的一个示例:Matrix.h, Eigen release 3.1 - David Hammen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接