如何使用 Doxygen 记录"enable_if"函数

How to document "enable_if" functions with Doxygen

本文关键字:if 函数 enable Doxygen 记录 何使用      更新时间:2023-10-16

在类Foo中,我有以下模板函数:

class Foo
{
  public:
    template <typename T>
    static typename boost::enable_if<boost::is_abstract<T>, T*>::type allocate();
    template <typename T>
    static typename boost::disable_if<boost::is_abstract<T>, T*>::type allocate();
};

有两个声明,但对于用户来说,只有一个函数。

用Doxygen记录此类声明的常用方法是什么

想法#1:

class Foo
{
  public:
    /** brief This function throws a runtime error */
    template <typename T>
    static typename boost::enable_if<boost::is_abstract<T>, T*>::type allocate();
    /** brief This function allocates an instance of the given type */
    template <typename T>
    static typename boost::disable_if<boost::is_abstract<T>, T*>::type allocate();
};

想法#2:

class Foo
{
  public:
    /** brief This function allocates an instance of the given type if not abstract, throws an exception instead */
    template <typename T>
    static typename boost::enable_if<boost::is_abstract<T>, T*>::type allocate();
    template <typename T>
    static typename boost::disable_if<boost::is_abstract<T>, T*>::type allocate();
};

我会用std::enable_if来回答这个问题,但它应该和boost::enable_if一样好用。

无论Doxygen是否在运行,您都可以使用包装enable_if的宏并以不同的方式定义它们。

在您的Doxyfile中,将以下内容添加到您的配置中:

PREDEFINED = GENERATING_DOXYGEN
EXPAND_AS_DEFINED = ENABLE_IF 
                    ENABLED_TYPE

在C++项目中,定义以下宏:

#ifdef GENERATING_DOXYGEN
#define ENABLE_IF(cond)
#define ENABLED_TYPE(T, cond) T
#else
#define ENABLE_IF(cond) typename std::enable_if<(cond)>::type
#define ENABLED_TYPE(T, cond) typename std::enable_if<(cond), T>::type
#endif

然后,您可以按如下方式使用宏:

class Foo
{
  public:
    /** brief Throws a runtime error
        tparam T An abstract type
        detail Only participates in overload resolution
                when std::is_abstract<T>::value==true */
    template <typename T>
    static ENABLED_TYPE(T*, std::is_abstract<T>::value) allocate();
    /** brief Allocates an instance of the given type
        tparam T A concrete type
        detail Only participates in overload resolution
                when std::is_abstract<T>::value==false */
    template <typename T>
    static ENABLED_TYPE(T*, !std::is_abstract<T>::value) allocate();
};

当Doxygen运行时,ENABLED_TYPE宏将扩展到未修饰的返回类型(在您的情况下为T*)。编译时,宏将扩展到std::enable_if<cond, T>::type以执行SFINAE。

您可能希望将宏命名为REQUIRES,而不是ENABLE_IF,以提高代码的可读性。您可能还想在宏前面加上项目名称,以避免与其他库中或任何超级项目中定义的宏发生冲突。


您还可以使用一个公共函数,然后对您的两种情况使用标记调度

class Foo
{
  public:
    /** brief Allocates an instance of the given type
        tparam T Must be a concrete type (checked at run time) */
    template <typename T>
    static T* allocate()
    {
      do_allocate(std::is_abstract<T>());
      // ...
    }
  private:
    template <typename T>
    T* do_allocate(std::false_type)
    {
      return new T;
    }
    template <typename T>
    T* do_allocate(std::true_type)
    {
      throw std::runtime_error("T must be concrete");
    }
};

使用C++17,您可以简单地执行if constexpr:

class Foo
{
  public:
    /** brief Allocates an instance of the given type
        tparam T Must be a concrete type (checked at run time) */
    template <typename T>
    static T* allocate()
    {
      if constexpr (std::is_abstract<T>())
      {
        throw std::runtime_error("T must be concrete");
      }
      else
      {
        return new T;
      }
    }
};