5

Bazネストされたクラスを含むテンプレートクラスがありますSub。std :: hashを特殊化して、このサブクラスのハッシュ関数を定義したいと思います。ただし、機能していないようです。

#include <functional>

struct Foo {
    struct Sub {
    };
};

template <class T>
struct Bar {
};

template <class T>
struct Baz {
    struct Sub {
        int x;
    };
};

// declare hash for Foo::Sub - all right
namespace std {
    template <>
    struct hash< Foo::Sub >;
}

// declare hash for Bar<T> - all right
namespace std {
    template <class T>
    struct hash< Bar<T> >;
}

// declare hash function for Baz<T>::Sub - doesn't work!
namespace std {
    template <class T>
    struct hash< Baz<T>::Sub >;
}

// Adding typename produces a different error.
namespace std {
    template <class T>
    struct hash< typename Baz<T>::Sub >;
}

Gcc 4.5.3は文句を言います:

$ g++ -std=c++0x -c hash.cpp
hash.cpp:34:30: error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::hash’
hash.cpp:34:30: error:   expected a type, got ‘Baz<T>::Sub’
hash.cpp:40:12: error: template parameters not used in partial specialization:
hash.cpp:40:12: error:         ‘T’

アップデート

私が実際にやろうとしているのは、その中の要素への安定した参照(C ++の意味ではない)をサポートするコンテナーを実装することです。ユーザーがこれらの参照をstd::unordered_set類似のものに挿入し、それらを使用して既存の要素に効率的にアクセスまたは変更できるようにしたいと思います。以下は単なるモックアップであり、私が実装している正確なコンテナではありません。問題は、参照タイプのハッシュ関数を定義することです。

template <class T>
class Container {
public:
    class Reference {
    public:
        // operator==, operator!=, operator< ...., isNull()
    private:
        size_t index; // index into m_entries (or could be anything else)
        // possibly more stuff
    };

    Reference insert (const T &value);
    Reference find (const T &value);
    void remove (Reference r);
    Reference first ();
    Reference next (Reference prev);

private:
    struct Entry { T value, ... };

    std::vector<Entry> m_entries;
};
4

3 に答える 3

4

コンテナからReferenceクラスを引き出すだけです。

template <class Container>
class Reference {
public:
    typedef typename Container::value_type value_type; // etc...

    // operator==, operator!=, operator< ...., isNull()
private:
    size_t index; // index into m_entries (or could be anything else)
    // possibly more stuff
};

template <class T>
class Container {
public:
    typedef ::Reference<Container> Reference;
    friend class Reference; // If you cannot help it

    typedef T value_type;

    Reference insert (const T &value);
    Reference find (const T &value);
    void remove (Reference r);
    Reference first ();
    Reference next (Reference prev);

private:
    struct Entry { T value, ... };

    std::vector<Entry> m_entries;
};

このように専門にします:

namespace std {
    template <typename Container>
    struct hash<Reference<Container>>;
}
于 2012-05-06T00:15:45.593 に答える
2

この質問への答えは、あなたがやろうとしていることは単に不可能であるということです。コンパイラーは、どの外部クラスにサブタイプが含まれているかを把握できません。理由を考えてみましょう。

struct outer1 { typedef int Sub; };
struct outer2 { typedef int Sub; };

コンパイラは、Subを取得するときに、どのアウターが必要かをどのように判断するのでしょうか。できない。これが機能するための可能な方法はありません。

あなたの場合、非常に困難ではありますが、Tに依存するIFF Subを導出することはリモートで可能です。しかし、これには、コンパイラがSubの出所を知る必要がありますが、そうではありません。

したがって、これを行うことはできません。まさか、まさか。

タイプのハッシュ関数を見つけるための一般的なアプローチが必要な場合は、メタ関数get_hashを作成する必要があります。デフォルトで「hash_type」内部typedefを検索し、標準のハッシュに対してオーバーライドできます。たくさんのタイピング...

または、Subをそれ自体のテンプレートとして含むクラスから外し、内部クラスの代わりにtypedefを配置します。次に、テンプレートでハッシュを特殊化できます。

それ以外の場合は、使用しているテンプレートのハッシュ関数パラメーターに必要なハッシュを指定するだけです。

于 2012-05-05T23:28:51.793 に答える
0

そのような依存型にテンプレートを特化することはできません。私はこのようなことを試みます。

struct yes {};

template <typename T>
yes accept_baz_sub(typename Baz<T>::Sub&&);
void accept_baz_sub(...);

template <class T>
struct is_baz_sub : std::is_same<decltype(accept_baz_sub(std::declval<T>())), yes>
{};

template <typename BazSub>
using CheckedBazSub = typename std::enable_if<is_baz_sub<BazSub>::value, BazSub>::type;

namespace std {
    template <class BazSub>
    struct hash<CheckedBazSub<BazSub>>;
}

編集:[temp.alias]§14.5.7.2によると、これは完全には機能しません。エイリアステンプレート名が推測されることはありません。

別の解決策は、独自のハッシュ関数オブジェクトを作成し、コンテナーにそれを使用させることです(std::unordered_mapたとえば、の3番目のテンプレートパラメーター)。

于 2012-05-05T23:09:57.073 に答える