2013-08-08 10 views
14

C++の(非常に多くの)残念な設計上の脆弱性の1つは、テンプレートメタプログラミングを使用すると実装からインタフェースを分離することは基本的に不可能です。これが読めない場合は、私はあなたを責めないでテンプレートの実装の詳細を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と定義するだけで、他のものであれば未定義になります(したがって、この演算子が他の重要なものを隠さないようにSFINAEに依存します)。

本質的に静的型チェックであるファンクションは、通常のC++関数のシグネチャに埋め込まれているので、これらの実装ガットは生成されたドキュメントに表示されます。

私はユーザーにこれを読んでもらう必要はありません。彼らが知る必要があるのは、この関数がboolを返すことです(これは上記を読んでほとんど分かりません)。ドキュメントでは、このオペレータが行列のみを受け入れることを簡潔に英語で簡単に説明することができます。

Doxygenにそのタイプの混乱をboolとするよう説得する方法はありますか? (私は、コード内でこれをきれいにする方法は多かれ少なかれあると仮定していますが、何かを考えることができれば、アイデアは大歓迎です)。

+0

私は「自動的に生成された」ドキュメントオーバー手書きの文書を好む理由があります。私はほとんどの場合、ドキュメントシステムをセットアップする/それを受け入れられるように修正するのにもっと多くの時間を費やしていますが、その間にすべてのドキュメンテーションを実際の素敵なフォーマットで書いたことがあります。 – orlp

+7

@ nightcracker:もちろん、ドキュメントを更新することなく、パラメータや関数などを変更するまでは。それから、それは同期しなくなり、役に立たないより悪くなります。また、Doxygenは手書きの文書をうまくサポートしています。 –

+2

おそらく関連している[this](http://stackoverflow.com/questions/3435225/c-meta-programming-doxygen-documentation)の質問です。 – elemakil

答えて

0

これはあなたのために働くかもしれないと思います。これはあなたよりも簡単な例ですが、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; 
} 
+0

SFINAEはテンプレート本体ではなくテンプレート署名にのみ適用されるため、これは同等ではありません。テンプレート本体の展開が無効な場合、コンパイラは他のテンプレートを試行しません。それは単にエラーと停止します。 – trbabb

+0

私は、この方法にはいくつかの制限があることに同意します。しかしコンパイラは私の例では 'test_hidden'の異なる実装を試みますが、場合によってはそれで十分です。私はこれを示すために私の答えを更新しました。 – dunc123

2

まあ、私はこれを達成することができる唯一の方法は、関数定義を複製するのではなく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); 
} 

のようにする必要があります。

#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++コードよりも理解読み取るためにさらに簡単です:についてどう

1

。 コンパイラが "Test"のコンマで区切られないように、最初のマクロ引数に二重括弧が付いていることに注意してください。戻り値の型(Type1)を最初に並べ替え、変数argマクロを使用してテストを行うと、それを取り除くことができます。

+1

私はコードの変更を強制する文書のファンではありません。 – Raffi

+1

私は同意しますが、その場合はマクロが実際に可視性を獲得します。コードの意味は、マクロではなく、マクロではっきりしています。 Doxygenによって実行されたときにマクロが動作を変更するという事実は、コードに良い利益をもたらします(コードを汚染したくない場合はDoxygenのスクリプトで行うことができます) – xryl669

1

返信タイプとしてboolを表示するようにDoxygenを説得してください:私が知っている唯一の方法は、実際の機能をDoxygen(これを行ういくつかの方法)から非表示にしたいというRaffiの答えです。

はクリーンアップ再:これは

bool_isEqualは、すべてのテンプレート型のロジックをカプセル化し、 typedeftype bool時に十分なまで
template <typename Ma, typename Mb> 
typename bool_isEqual<Ma, Mb>::type 
operator==(const Ma &a, const Mb &b) 
... 

のようになります。 (名前bool_isEqualは、boolを返すが、他の条件を持つ同様の構造を持つ他のテンプレート関数があると仮定されているため選択されます。)

これが一貫して行われると、おそらく十分に読み込み可能です。

1

私は以下の方法は非常に明確であることが判明:Doxyfileという中

  1. は、ソースコードでは= Doxygenの
  2. PREDEFINEDを追加するには///@cond .... ///@endcond
  3. でSFINAE機能を囲むあなたのソースのシンプルなテンプレート関数宣言を置きますコードは#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 
    
関連する問題