だから私は自動を書きたい!=
:
template<typename U, typename T>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
しかし、それは失礼です1。だから私は書く
// T() == U() is valid?
template<typename T, typename U, typename=void>
struct can_equal:std::false_type {};
template<typename T, typename U>
struct can_equal<
T,
U,
typename std::enable_if<
std::is_convertible<
decltype( std::declval<T>() == std::declval<U>() ),
bool
>::value
>::type
>: std::true_type {};
t == u
これは、「変換可能な型を返す有効なコードである」という型特性クラスですbool
。
だから私は自分を改善します!=
:
template<typename U, typename T,
typename=typename std::enable_if<can_equal<T,U>::value>::type
>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
現在は、存在する場合にのみ有効なオーバーライドです==
。悲しいことに、それは少し貪欲です:
struct test {
};
bool operator==(const test&, const test&);
bool operator!=(const test&, const test&);
上記が呼び出されるtest() != test()
のではなく、ほぼ毎回スナーフするためです。!=
これは望ましくないと思います-!=
自動転送し==
て否定するよりも、明示的に呼び出したいと思います。
だから、私はこの特性クラスを書きます:
template<typename T, typename U,typename=void>
struct can_not_equal // ... basically the same as can_equal, omitted
が有効かどうかをテストしT != U
ます。
次に、次のように拡張!=
します。
template<typename U, typename T,
typename=typename std::enable_if<
can_equal<T,U>::value
&& !can_not_equal<T,U>::value
>::type
>
bool operator!=(U&& u, T&& t) {
return !( std::forward<U>(u) == std::forward<T>(t) );
}
これを解析すると、「この文は誤りです」と表示されます --と の間に存在し、とoperator!=
の間T
にU
iffoperator!=
は存在しません。T
U
驚くことではありませんが、私がテストしたすべてのコンパイラは、これを入力するとセグメンテーション違反を起こしました。(clang 3.2、gcc 4.8 4.7.2 インテル 13.0.1)。 私がやっていることは違法だと思いますが、標準のリファレンスを見てみたいです。(編集: 制限のない再帰的なテンプレート展開を誘発するため、私がやっていることは違法です。適用されるかどうかを判断するには、!=
適用されるかどうかを確認する必要があるためです。!=
#if 1
しかし、私の質問: SFINAE ベースのオーバーライドが失敗するかどうかを判断するときに「それ自体」を無視するように説得する方法、または何らかの形で自己参照の問題を取り除く方法はありますか? operator!=
または、私のローの優先順位を十分に下げて、!=
それ以外の場合はそれほど良くない場合でも、明示的なものが勝つようにしますか?
「存在しない」ことをチェックしないものは!=
かなりうまく機能しますが、それをグローバル名前空間に挿入するほど失礼になるには十分ではありません。
目標は、私の「魔法」が導入されると、私の「魔法」なしでコンパイルされるコード!=
がまったく同じことを行うことです。それ以外の場合は無効であり、私の「魔法」が作動した!=
場合にのみ適切に形成されます.!=
bool r = !(a==b)
!=
脚注1 : を作成するtemplate<typename U, typename T> bool operator!=(U&& u, T&& t)
と、SFINAE は型のすべてのペアが!=
それらの間で有効であると見なします。次に、実際に を呼び出そうとすると!=
、インスタンス化されてコンパイルに失敗します。それに加えて、とbool operator!=( const foo&, const foo& )
により適しているため、関数を踏みにじります。私はこれらの両方を失礼だと考えています。foo() != foo()
foo a, b; a != b;