Скрыть детали реализации шаблонов от Doxygen
Один из (так много) неудачных недостатков дизайна С++ заключается в том, что в принципе невозможно отделить реализацию от интерфейса при использовании метапрограммирования шаблонов.
Во всей библиотеке у меня есть такие вещи, как:
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
, если аргументы являются матрицами и соответствием размерности, и undefined, если они что-то другое (таким образом, полагаясь на SFINAE, чтобы этот оператор не скрывал другие важные вещи).
Так как кишки того, что по существу является статической функцией проверки типов, теперь встроены в подпись моей обычной функции С++, эти кишки реализации появятся в сгенерированной документации.
Я не хочу, чтобы пользователь должен был прочитать это. Все, что им нужно знать, это то, что эта функция возвращает bool
(что почти невозможно сказать, прочитав выше). В документах я могу кратко, на простом английском языке, объяснить, что этот оператор принимает только матрицы.
Есть ли способ убедить Doxygen сделать этот беспорядок типа bool
? (Я предполагаю, что более или менее нет возможности очистить это в коде напрямую, но идеи приветствуются, если вы можете что-то придумать).
Ответы
Ответ 1
Ну, единственный способ добиться этого - дублировать определение функции, а не использовать автоматическую функцию doxygen и использовать @fn
. Для вашего примера, что-то вроде
/*[email protected] 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);
}
.
Ответ 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); }
IMHO, это еще проще читать и понимать, чем исходный код на С++.
Обратите внимание на двойную скобку в первом аргументе макроса, чтобы компилятор не разбивал запятую в "Тесте". Вы можете избавиться от него, если сначала измените порядок возвращаемого типа (Type1) и используйте переменную arg macro для теста.
Ответ 3
Попробуйте Doxygen показать bool
как возвращаемый тип: единственный способ, которым я знаю, - это ответ Раффи, добавив, что вы, вероятно, захотите скрыть действительную функцию от Doxygen (несколько способов сделать это).
Повторная очистка: это может выглядеть примерно так:
template <typename Ma, typename Mb>
typename bool_isEqual<Ma, Mb>::type
operator==(const Ma &a, const Mb &b)
...
Где bool_isEqual
инкапсулирует все логики типа шаблона и typedef
type
в bool
, когда это необходимо. (Имя bool_isEqual
выбрано потому, что предполагается, что другие функции шаблона имеют аналогичную структуру, которые возвращают bool
, но имеют другие условия.)
Если это будет сделано последовательно, это, вероятно, достаточно читаемо.
Ответ 4
Я нашел следующий метод очень ясным:
- В Doxyfile добавить PREDEFINED = DOXYGEN
- В исходном коде функции объемного звучания SFINAE с помощью
///@cond .... ///@endcond
-
Поместите простое выражение о шаблонных функциях в исходный код в #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
Ответ 5
Я думаю, это может сработать для вас. Очевидно, что это более простой пример, чем ваш, но основная идея использования документированной функции шаблона без 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;
}