如何使用 Doxygen 记录“enable_if”函数

Cad*_*hon 6 c++ templates doxygen

在类中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();
};
Run Code Online (Sandbox Code Playgroud)

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

使用 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();
};
Run Code Online (Sandbox Code Playgroud)

想法#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();
};
Run Code Online (Sandbox Code Playgroud)

Emi*_*ier 1

我会用 来回答这个问题std::enable_if,但它应该与 一样有效boost::enable_if

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

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

PREDEFINED = GENERATING_DOXYGEN

EXPAND_AS_DEFINED = ENABLE_IF \
                    ENABLED_TYPE
Run Code Online (Sandbox Code Playgroud)

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

PREDEFINED = GENERATING_DOXYGEN

EXPAND_AS_DEFINED = ENABLE_IF \
                    ENABLED_TYPE
Run Code Online (Sandbox Code Playgroud)

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

#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
Run Code Online (Sandbox Code Playgroud)

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

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


您还可以做的是拥有一个公共函数,然后针对两种情况使用标签调度:

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();
};
Run Code Online (Sandbox Code Playgroud)

使用 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()
    {
      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");
    }
};
Run Code Online (Sandbox Code Playgroud)