Doxygen 抱怨递归 C++ class

Doxygen complains about recursive C++ class

我有一个实现欧几里德算法(优化版本)的简单递归模板。 Doxygen 抱怨它:

/usr/home/kamikaze/stark/Yggdrasil/src/units/Units.hpp:335: warning: Detected potential recursive class relation between class units::euclid and base class units::euclid< Rhs, Lhs%Rhs >!

/usr/home/kamikaze/stark/Yggdrasil/src/units/Units.hpp:335: warning: Detected potential recursive class relation between class units::euclid and base class euclid< Rhs, Lhs%Rhs >!

/usr/home/kamikaze/stark/Yggdrasil/src/units/Units.hpp:335: warning: Detected potential recursive class relation between class units::euclid and base class units::euclid< Rhs, Lhs%Rhs >!

/usr/home/kamikaze/stark/Yggdrasil/src/units/Units.hpp:335: warning: Detected potential recursive class relation between class units::euclid and base class euclid< Rhs, Lhs%Rhs >!

我傻眼了,为什么那是 complaint/warning。我认为递归类型是常见且合法的。它也是许多递归模板之一,但唯一一个 doxygen 抱怨。 令我惊讶的是,我只发现了 doxygen 错误检测递归的类似问题。

如果你有兴趣,这里是代码:

/**
 * Implements Euclid's algorithm to find the GCD between two integers.
 *
 * @tparam Lhs,Rhs
 *  The values to get the GCD for
 */
template <int Lhs, int Rhs>
struct euclid : euclid<Rhs, Lhs % Rhs> {
};

/**
 * Terminates Euclid's algorithm.
 *
 * @tparam Gcd
 *  The GCD to return
 * @see euclid
 */
template <int Gcd>
struct euclid<Gcd, 0> {
    /**
     * The GCD of the two original values.
     */
    static constexpr int const value{Gcd};
};

这个构造确实超出了 doxygen 的解析能力。

由于此 class 的用户没有兴趣知道它是以递归方式实现的,您可以使用以下解决方法:

/**
 * Implements Euclid's algorithm to find the GCD between two integers.
 *
 * @tparam Lhs,Rhs
 *  The values to get the GCD for
 */
template <int Lhs, int Rhs>
struct euclid /** @cond */ : euclid<Rhs, Lhs % Rhs> /** @endcond */ {
  /** @cond */
};

template <int Gcd>
struct euclid<Gcd, 0> {
  /** @endcond
   * The GCD of the two original values.
   */
  static constexpr int const value {Gcd};
};

默认情况下,doxygen 没有完整的 C++ 解析器。所以它可能会得到错误的有效 C++ 代码。

因为 doxygen 1.8.4 it is possible to configure doxygen 使用来自 Clang 的 C++ 解析器,它应该可以解析大部分真实世界的 C++ 代码。

事先声明模板会有什么不同吗?在定义点上,唯一可能的基础 class 确实是递归的。我会这样组织代码,不仅是为了让 Doxygen 高兴,还因为我还首先与基本情况建立了数学归纳和递归关系:

// forward declaration
template <int Lhs, int Rhs>
struct euclid;

// base case
template <int Gcd>
struct euclid<Gcd, 0>
{
    static constexpr int const value{Gcd};
};

// recurrence relation
template <int Lhs, int Rhs>
struct euclid : euclid<Rhs, Lhs % Rhs>
{
};