One of the (so very many) unfortunate design flaws of C++ is that it is basically impossible to separate implementation from interface when using template metaprogramming.
All over my library I have things like:
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);
}
If this is unreadable, I don't blame you. Most of this mess is simply defining the return type to be bool if the arguments are matrices and match dimension, and be undefined if they are something else (thus relying on SFINAE to prevent this operator from hiding other important things). 
Since the guts of what is essentially a static type-checking function are now embedded into the signature of my ordinary C++ function, these implementation guts will appear in the generated documentation.
I don't want the user to have to read this. All they need to know is that this function returns a bool (which is almost impossible to tell by reading the above). In the docs, I can explain succinctly, in plain English, that this operator accepts only matrices.
Is there a way to persuade Doxygen to render that type mess as bool? (I'm assuming there is more or less no way to clean this up in the code directly, but ideas are welcome if you can think of something). 
What about:
#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); }
IMHO, it's even easier to read & understand than the initial C++ code. Please notice the double parenthesis in the first macro argument to avoid the compiler to break on the comma in the "Test". You can get rid of it if you reorder the return type first (Type1), and use variable arg macro for the test.
Well, the only way I may achieve this is by duplicating the function definition rather than using the automatic feature of doxygen, and using the @fn command instead. For your example, something like
/*!@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);
 }
should do.
Re persuading Doxygen to show bool as return type: The only way I know of is Raffi's answer, adding that you then probably want to hide the actual function from Doxygen (several ways to do this).
Re cleaning up: This could look something like
template <typename Ma, typename Mb>
typename bool_isEqual<Ma, Mb>::type 
operator==(const Ma &a, const Mb &b)
...
Where bool_isEqual encapsulates all the template type logic and typedefs type to bool when adequate. (The name bool_isEqual is chosen because there are assumed to be other template functions with a similar structure that return bool but have other conditions.)
If this is done consistently, it is probably readable enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With