隐藏Doxygen的模板实现细节

时间:2013-08-08 08:13:14

标签: c++ templates doxygen

C ++的一个(如此之多)令人遗憾的设计缺陷是,在使用模板元编程时,基本上不可能将实现与接口分开。

我的图书馆遍布:

template <typename Ma, typename Mb>
typename boost::enable_if_c<
            detail::IsMatrix<Ma>::val and detail::IsMatrix<Mb>::val and
            detail::MatrixDimensionCheck<Ma,Mb>::isStaticMatch, 
        bool>::type
operator==(const Ma &a, const Mb &b) {
    return detail::matrixEqual(a,b);
}

如果这是不可读的,我不会责怪你。如果参数是矩阵并匹配维度,那么大多数混乱只是将返回类型定义为bool,如果它们是其他东西则是未定义的(因此依赖SFINAE来防止此运算符隐藏其他重要事物)。

由于本质上是静态类型检查函数的内容现已嵌入到我的普通C ++函数的签名中,因此这些实现内容将出现在生成的文档中。

我不希望用户必须阅读此内容。他们需要知道的是,这个函数返回bool(通过阅读上面的内容几乎不可能知道)。在文档中,我可以用简单的英语简洁地解释该运算符只接受矩阵。

有没有办法说服Doxygen将这种类型的混乱呈现为bool? (我假设在代码中或多或少没有办法在代码中直接清除它,但如果你能想到某些东西,欢迎这些想法)。

5 个答案:

答案 0 :(得分:2)

嗯,我实现这一目标的唯一方法是复制函数定义而不是使用doxygen的自动功能,而是使用@fn命令。对于你的例子,像

/*!@fn template <typename Ma, typename Mb> bool operator==(const Ma &a, const Mb &b)
 * @brief My equality operator
 * @note The operator is available if the types @c Ma and @c Mb match. 
 *       It will be discarded otherwise 
 */
 template <typename Ma, typename Mb>
   typename boost::enable_if_c<
     detail::IsMatrix<Ma>::val and detail::IsMatrix<Mb>::val and
     detail::MatrixDimensionCheck<Ma,Mb>::isStaticMatch, 
   bool>::type
 operator==(const Ma &a, const Mb &b) {
    return detail::matrixEqual(a,b);
 }

应该这样做。

答案 1 :(得分:2)

怎么样:

#ifdef DOXYGEN
    #define RETURN_TYPE(Test, Type1) Type1
#else
    #define RETURN_TYPE(Test, Type1) typename boost::enable_if_c< Test, Type1 >::type
#endif

template <typename Ma, typename Mb>
RETURN_TYPE((detail::IsMatrix<Ma>::val 
        and detail::IsMatrix<Mb>::val 
        and detail::MatrixDimensionCheck<Ma,Mb>::isStaticMatch), bool) 
operator==(const Ma &a, const Mb &b) { return detail::matrixEqual(a,b); }

恕我直言,它更容易阅读&amp;理解比最初的C ++代码。 请注意第一个宏参数中的双括号,以避免编译器在“Test”中的逗号上中断。如果首先重新排序返回类型(Type1),并使用变量arg宏进行测试,则可以删除它。

答案 2 :(得分:1)

重新说服Doxygen将bool显示为返回类型:我所知道的唯一方法是Raffi的回答,并补充说你可能想要隐藏Doxygen的实际功能(有几种方法可以做到这一点)。

重新清理:这看起来像

template <typename Ma, typename Mb>
typename bool_isEqual<Ma, Mb>::type 
operator==(const Ma &a, const Mb &b)
...

bool_isEqual在适当时将所有模板类型逻辑和typedef s type封装到bool。 (选择名称bool_isEqual是因为假设其他模板函数具有返回bool但具有其他条件的类似结构。)

如果这是一致的,那么它可能足够可读。

答案 3 :(得分:1)

我发现以下方法非常明确:

  1. 在Doxyfile中添加PREDEFINED = DOXYGEN
  2. 在您的源代码环绕SFINAE函数///@cond .... ///@endcond
  3. #ifdef DOXYGEN内的源代码中放入一个简单的模板化函数声明,因此它对于正常编译是不可见的。观察:

    ///@cond
    template <typename Ma, typename Mb>
    typename boost::enable_if_c<
        detail::IsMatrix<Ma>::val and detail::IsMatrix<Mb>::val and
        detail::MatrixDimensionCheck<Ma,Mb>::isStaticMatch, 
        bool>::type
    operator==(const Ma &a, const Mb &b) {
        return detail::matrixEqual(a,b);
    }
    ///@endcond
    #ifdef DOXYGEN
        ///Documentation for your function...
        template<typename Ma, typename> operator==(const Ma &a, const Mb &b);
    #endif
    

答案 4 :(得分:-1)

我认为这可能适合你。显而易见它是一个比你更简单的例子,但是使用没有enable_if的文档化模板函数来调用另一个“隐藏”函数的基本思想是没有记录但提供了SFINAE。

// Ignore this function in doxygen
template <typename T>
typename boost::enable_if<boost::is_unsigned<T>, bool>::type
test_hidden(T t) {
    return true;
}

template <typename T>
typename boost::disable_if<boost::is_unsigned<T>, bool>::type
test_hidden(T t) {
    return false;
}

// Document this function
template <typename T>
bool test(T t)
{
    return test_hidden(t);
}

int main()
{
   unsigned int a = 1;
   int b = 0;

   std::cout << test(a) << std::endl; // true
   std::cout << test(b) << std::endl; // false

   return 0;
}