6

とにかく、このようなテンプレートを特殊化して、Tにメンバー関数がある場合にのみ特殊化を適用することはできますhashか?(これは私がやろうとしていることのほんの一例であることに注意してください。メンバー関数hashでそれ自体をチェックする関数を持つ各クラスの方が理にかなっていることはわかっていますoperator==が、この種かどうかを知りたいだけです。物事の可能性があります。)

template <class T>
bool equals(const T &x, const T &y)
{
    return x == y;
}

template <class T> // somehow check if T has a member function 'hash'
bool equals<T>(const T &x, const T &y)
{
    return x.hash() == y.hash() && x == y;
}

可能であれば、C++11より前のソリューションをお勧めします。

4

2 に答える 2

8

これが私自身のコードの例です。構造名の1つから推測できるように、これは置換の失敗はエラーではないという原則に基づいています。構造体has_member_setOriginは、の2つのバージョンを定義しますtestUメンバーがいない場合、最初のものは満たすことができませんsetOriginこれはテンプレート置換のエラーではないため、存在しないかのように機能します。したがって、ポリモーフィック関数の解決順序はtest(...)、そうでなければ優先度が低いものを見つけます。次にvalue、の戻りタイプによって決定されtestます。

これに続いて、テンプレートを使用したcallSetOrigin(のと同等の)2つの定義があります。調べると、最初のテンプレート引数がtrueの場合は定義され、そうでない場合は定義されていないことがわかります。これにより、定義の1つに置換エラーが発生し、1つだけが存続します。equalsenable_ifenable_ifenable_if<...>::typecallSetOrigin

template <typename V>
struct has_member_setOrigin
{
    template <typename U, void (U::*)(const Location &)> struct SFINAE {};
    template <typename U> static char test(SFINAE<U, &U::setOrigin>*);
    template <typename U> static int test(...);
    static const bool value = sizeof(test<V>(0)) == sizeof(char);
};

template<typename V>
void callSetOrigin(typename enable_if <has_member_setOrigin<V>::value, V>::type &p, const Location &loc) const
{
    p.setOrigin(loc);
}

template<typename V>
void callSetOrigin(typename enable_if <!has_member_setOrigin<V>::value, V>::type &p, const Location &loc) const
{
}

私も定義を提供したことを忘れenable_ifました:

#ifndef __ENABLE_IF_
#define __ENABLE_IF_

template<bool _Cond, typename _Tp>
struct enable_if
{ };

template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };

#endif /* __ENABLE_IF_ */
于 2012-06-19T19:14:52.167 に答える
2

C++11ソリューション。を含む有効なタイプのみになるように、戻りタイプを変更するだけです.hash。また、コンマ演算子を使用して、コンパイラが計算できることを確認している間、declval<T>.hash()実際にはそれを無視して、タイプtrue、もちろんbool、必要なタイプを使用します。

template <class T>
auto equals(const T &x, const T &y) -> decltype(declval<T>.hash(), true)
{
    return x.hash() == y.hash() && x == y;
}

これはExpressionSFINAEと呼ばれていると思います。

詳細:

decltype(X,Y)と同じですdecltype(Y)(コンマ演算子に感謝します)。つまり、ここでの私の返品タイプは、基本的decltype(true)に、つまりbool、必要に応じてです。それで、なぜ私は持っているのdeclval<T>.hash()ですか?それは単なるスペースの無駄ではありませんか?

答えはThash方法があるのはテストだということです。このテストが失敗すると、戻り型の計算が失敗するため、関数は有効なオーバーロードとは見なされず、コンパイラーは他の場所を探します。

最後に、これまでに見たことがない場合は、評価されていないコンテキスト(など)declvalでタイプのオブジェクトを作成するのに非常に便利な方法です。を作成するために書きたくなるかもしれません。したがって、を呼び出すために使用します。ただし、デフォルトのコンストラクターがない場合は機能しません。これを解決します。TdecltypeT()TT().hash()hashTdeclval

于 2015-02-01T19:16:49.590 に答える