1

このコードを可能にしたいです。

template<typename K, typename T, typename Comparer>
class AVLTree
{
   ...
   void foo() {
       ...
       int res = Comparer::compare(key1, key2);
       ...
   }
   ...
};

具体的には、 Comparer クラスにstatic int compare(K key1, K key2)機能を持たせたいと思っています。派生を使おうと考えていたのですが、テンプレートでうまくいくアイデアが見つかりませんでした。

ありがとうございました。

4

8 に答える 8

5

できません。しかし、関数を使用し、Comparer がそれを持っていない場合、コンパイルは失敗し、これは多かれ少なかれあなたが望んでいることです。はい、他の人が指摘したように、 static を static と呼びたいです。

于 2009-12-26T12:28:52.693 に答える
4

やってみましたか:

   int res = Comparer::compare(key1, key2);

C++ では、静的関数は次の 2 つの方法で呼び出すことができます。

object.static_method(); // use dot operator

classname::static_method(); // use scope resolution operator
于 2009-12-26T12:20:51.497 に答える
2

マイケルは、必要なメンバー関数がない場合、これはコンパイルされないことをすでに述べました。Comparer

ただし、簡潔なエラー メッセージの方が心配な場合は、次のようなものを使用して、クラスに必要なメンバー関数があるかどうかを検出し、それを Boost.StaticAssert などと組み合わせます

template<typename K, typename T, typename Comparer>
class AVLTree
{
    BOOST_STATIC_ASSERT(HasCompareMethod<Comparer>::has);
    //...
};
于 2009-12-26T12:51:05.317 に答える
1

より慣用的で一般的なアプローチは次のとおりです。

template<typename K, typename T>
class AVLTree
{
   ...
   template <typename Comparer>
   void foo(Comparer cmp) {
       ...
       int res = cmp(key1, key2);
       ...
   }
   ...
};

CompareComparerは、静的メソッドを定義する型であってはなりません。関数呼び出し構文で呼び出すことができるタイプである必要があります。これにより、関数オブジェクトの関数ポインターを使用できるようになり、標準ライブラリまたはその他の重要なC++アプリケーションで既に定義されている比較子を再利用できるようになります。これにより、ラムダがC++0xで追加されたときにラムダを使用できます。

Comparer期待通りに振る舞うことを強制することについては?行int res = cmp(key1, key2);はすでにそれを保証します。この方法で呼び出すことができない型を渡そうとすると、コンパイルエラーが発生します。

元のコードでも同じことが言えました。静的メソッドを持たない型を渡した場合Compare、コンパイルエラーが発生します。したがって、元のコードはすでに問題を解決しています。

于 2009-12-26T21:40:16.003 に答える
1

テンプレート パラメーターがテンプレート本体の要件に適合しない場合に備えて、より適切なエラー メッセージを探していることは理解しています。言語にはそのための特別なメカニズムが組み込まれていませんが、人々はライブラリを使用して近似します。ブーストコンセプトチェックを参照

于 2009-12-26T12:52:44.830 に答える
1

である必要がありComparer::Compareますよね?(型で静的関数を呼び出しているため)。

Comparer クラスは次のように定義する必要があります。

template<typename K>
class Comparer
{
public:
    static bool Compare(K key, K key)
    {
        return true;
    }
};
于 2009-12-26T12:21:40.960 に答える
1

これをコンパイル時にアサーションする緩いアプローチは、Comparer::compare のアドレスを取得し、int(K, K) *func として宣言された変数に割り当てることです。

その割り当ては、静的関数の場合は機能しますが、メンバー関数の場合は機能しません。

私はこれに貢献しているだけですが、いわば手巻きなので、ブーストイディオムを使用するアプローチを取ります.

于 2009-12-26T12:59:18.063 に答える
0

既に指摘したように、Compare に強制的に static member を持たせることはできませんcompare。比較子がそれを実装していない場合は、コンパイル エラーが発生します。

このように実装する場合は、テンプレート テンプレート パラメータとしてAVLTree宣言する方がエレガントです。Comparer

template <typename K>
class DefaultComparer
{
public:
    static bool compare(K k1, K k2)
    { return k1 == k2; }
};

template <typename K>
class MyComparer : public DefaultComparer<K>
{
public:
    static bool compare(K k1, K k2)
    { return k1 <= k2; }
};

template <typename K>
class InvalidComparer
{
public:
    static bool bar(K k1, K k2)
    { return k1 != k2; }
    // Doesn't implement compare()
};

// Compare is a template template paramenter with default template argument
// DefaultComparer
template <typename K, template <typename K> class Comparer = DefaultComparer>
class AVLTree
{
    K k1, k2;
public:
    AVLTree() : k1(0), k2(0) { } // ctor
    bool foo();
};

// Definiton of AVLTree::foo()
template <typename K, template <typename K> class Comparer>
bool AVLTree<K, Comparer>::foo()
{
    return Comparer<K>::compare(k1, k2);
}

int main(int argc, char *argv[])
{
    // Without template template parameters you 
    // would have to use AVLTree<int, DefaultComparer<int> >
    AVLTree<int> avltree;

    // instead of AVLTree<int, MyCompare<int> >
    AVLTree<int, MyComparer> avltree2;

    // Calling foo() will generate a compile error. 
    // But if you never call avltree3.foo() this will compile!
    AVLTree<int, InvalidComparer> avltree3;

    avltree.foo(); // calls DefaultComparer::compare
    avltree2.foo(); // calls MyComparer::compare
    avltree3.foo(); // fails to compile
}

参照: http://codepad.org/OLhIPjed

于 2009-12-26T14:49:12.440 に答える