3

例えば

template <class T1, class T2>
class foo
{
    T1 t1;
    T2 t2;

    T1 bar(); //Always exists
    decltype(t1(t2)) baz(); //Should only exist if t1(t2) is valid
};

が無効な場合bazでも、実際に誰も呼び出さない限り、プログラムをコンパイルしたいと考えていますbaz

4

1 に答える 1

4

baz戻り値の型が無効な場合、ハード エラーが発生するのではなく、メンバーが SFINAE で出力されるように、テンプレートを作成できます。

template <class T1, class T2>
class foo
{
    T1 t1;
    T2 t2;

    T1 bar(); //Always exists

    template<typename T = T1>
    decltype(std::declval<T&>()(t2)) baz();
};

このTパラメーターは、計算式をタイプ依存にするために必要です。そうしないと、SFINAE は適用されません。この実装の詳細が「漏れ」 f.baz<int>()、誰かbazが. どちらのアプローチでも、メンバーのアドレスを取得するのが難しくなります。たとえば、 のようになります。template<typename... Dummy, typename T = T1>static_assert( sizeof...(Dummy) == 0, "Incorrect usage" );&foo<T, U>::baz<>

もう 1 つのアプローチは、クラス テンプレートの特殊化を導入することです。

template<typename...> struct void_ { using type = void; };

template<typename T1, typename T2, typename = void>
class foo {
    // version without baz
};

template<typename T1, typename T2>
class foo<T1, T2, typename void_<decltype(std::declval<T1&>()(std::declval<T2>()))>::type> {
    decltype(std::declval<T1&>()(std::declval<T2>())) baz();
};

この場合&foo<T, U>::baz、メンバーのアドレスを取得するのに問題はありません (もちろん存在すると仮定します)。両方の特殊化に共通するコードは、共通のベースに分解できます。また、実装の詳細として導入された追加のテンプレート パラメータが漏れる心配がある場合は、テンプレート パラメータをfoo2 つだけ取る「本物」を作成することができます。次に、そのような実装から継承します。

于 2012-10-24T05:10:15.440 に答える