2016-10-12 7 views
0

this (un)problemを解決しようとしている間に、boolが偽であり、その値が!(値ではない)も偽であるということを、間に合わせて非常に奇妙な動作に気付きました。私はこれがどのように可能であるか知りたいです。この原因コードは次のとおりです。ブールとそれ以外の値はどちらもfalseになりますか?

template<typename T, typename TID = unsigned int> 
struct AId { 
    typedef AId<T, TID> type; 
    typedef T handled_type; 
    typedef TID value_type; 

private: 
    value_type id; 

    template<typename _T> struct IsIncrementable 
    { 
    template<typename _U> using rm_ref = typename std::remove_reference<_U>::type; 
    typedef char (&yes)[1]; 
    typedef char (&no)[2]; 
    template<class _U> 
    static yes test(_U *data, typename std::enable_if< 
         std::is_same<_U, rm_ref<decltype(++(*data))>>::value 
        >::type * = 0); 
    static no test(...); 
    static const bool value = sizeof(yes) == sizeof(test((rm_ref<_T> *)0)); 
    }; 

public: 
    explicit AId(const value_type &id) : id(id) {} 

... 

    //IsIncrementable<value_type>::value is false: 
    //error: no type named 'type' in 'struct std::enable_if<false, int>' 
    template<typename std::enable_if<IsIncrementable<value_type>::value, int>::type = 0> 
    type operator++(int /*postfix*/) { type old(id); ++id; return old; } 

    //!IsIncrementable<value_type>::value is also false: 
    //error: no type named 'type' in 'struct std::enable_if<false, int>' 
    template<typename std::enable_if<!IsIncrementable<value_type>::value, int>::type = 0> 
    type operator++(int /*postfix*/) { type old(id); ++id; return old; } 
}; 

それはどのようにIsIncrementable<value_type>::valueがfalseで!IsIncrementable<value_type>::valueも虚偽である可能性がありますか?

+0

コード内のコメントを参照してください。エラーは両方ともenable_if です。したがって、enable_ifの両方の引数はfalseです。 – Olivetree

+0

これを見ると、バリーの答えはあなたが[ここ](https://stackoverflow.com/questions/39998793/sfinae-to-have-a-class-member-only-if-possible)で参照した問題を解決し、私よりも簡単な答えです。 –

+0

@Guillaume Racicotので、他のSFINAEの使用にも誤認はありませんか? (あまり面白い事実ではない:私はすでに前に似たようなコードを使用していたが、別のアプローチに賛成でそれを落として、もはやそれを持っていなかった) – Olivetree

答えて

0

これは、問題がテンプレートのコード内ではなく、インスタンス化されているため、おそらく他のメンバーにとって不公平です。

@なぜ、SFINAEがここではうまくいかず、代わりにハードエラーが発生する理由がBarry's answearによって説明されています。しかし、私が関数を次のように置き換えた場合:

static_assert(IsIncrementable<value_type>::value, "It cannot be incrementable"); 
    static_assert(!IsIncrementable<value_type>::value, "It has to be incrementable"); 

私はまだ両方のアサーションでエラーが発生します。問題は、2つの異なるクラスを使用してテンプレートをインスタンス化していたことです。あるケースの場合、IsIncrementable<value_type>::valuetrueであり、他方はIsIncrementable<value_type>::valueであり、falseであった。エラーがfalseに表示されるので、これは常に偽であるという印象を与えました。さらに!値です。

4

SFINAEはのテンプレートインスタンシエーションの直後のコンテキストにのみ適用されます。

template <class T> 
struct X { 
    template <std::enable_if_t<std::is_pointer<T>::value, int> = 0> 
    void foo() { 
    } 
}; 

Tがすでにfooがインスタンス化されるまでに知られているので、その関数テンプレートの置換の際に起こる故障ではありません。ここでは短い例です。これは難しいエラーです。 fooに電話するかどうかにかかわらず、enable_if_t<false, int>が既に不正であるため、X<int>をインスタンス化することはできません。

あなたが実際に即時の文脈の中に落ちる不履行の型パラメータを導入する必要があります:

template <class T> 
struct X { 
    template <class U=T, std::enable_if_t<std::is_pointer<U>::value, int> = 0> 
    void foo() { 
    } 
}; 

は今、UにSFINAE-INGのは結構です - Uので、この関数へのローカルテンプレートパラメータでありますそのインスタンス化はまで遅延されます。この関数が使用されます。従ってX<int>{}は正常であり、オーバーロード解決が実行可能な過負荷を見つけることができないのでX<int>{}.foo()は失敗します - このfoo()はちょうど削除されました。

+0

これはSFINAEが私のコードではうまくいかない理由についての良い説明ですが、bool値がどのようにfalseで、 '! 'もfalseであるのかという疑問に答えません。私がコードを変更した場合、 – Olivetree

+0

@TobySpeightうん、ありがとう。 – Barry

+0

(入力前にシフトを忘れてしまった、コメントを編集できません) 'static_assert(IsIncrementable ::「値を増分することはできません」); 'static_assert(!IsIncrementable ::値 "インクリメント可能でなければなりません"); ' それでもコンパイルされません。私は今、私はこの展覧会を機能の代わりに選択すべきだったことを認識しています。 – Olivetree

関連する問題