17

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++ 函数的签名中,因此这些实现内容将出现在生成的文档中。

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

有没有办法说服 Doxygen 将这种类型的混乱渲染为bool? (我假设或多或少没有办法直接在代码中清理它,但如果你能想到一些想法,欢迎提出想法)。

4

5 回答 5

3

关于什么:

#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); }

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

于 2013-09-11T13:16:25.910 回答
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);
 }

应该做。

于 2013-08-25T23:11:51.773 回答
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
    
于 2014-03-27T12:30:01.653 回答
1

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

重新清理:这可能看起来像

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

Wherebool_isEqual封装了所有的模板类型逻辑,并在适当的时候封装了typedefs typeto 。bool(之所以选择这个名称bool_isEqual,是因为假设有其他具有类似结构的模板函数返回bool但具有其他条件。)

如果始终如一地这样做,它可能就足够可读了。

于 2013-12-09T19:41:46.987 回答
-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;
}
于 2013-08-08T09:36:18.317 回答