6

私は次のような非メンバー演算子関数テンプレートを書き込もうとしています:

#include <utility>

template < typename T, unsigned L >
class MyType;

template < typename T, typename U, unsigned L >
auto  operator ==( MyType<T,L> const &l, MyType<U,L> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

しかし、私がいつ処理しようとするlと、r長さが異なります:

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt < Lu)>::type >
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt > Lu)>::type >
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

あいまいなエラーが発生します。私は次のようなことを試しました:

template < typename T, unsigned Lt, typename U, unsigned Lu, bool B = (Lt < Lu), class Enable = typename std::enable_if<B>::type >
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

template < typename T, unsigned Lt, typename U, unsigned Lu, bool B = (Lt > Lu), class Enable = typename std::enable_if<B>::type >
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

メンバー関数テンプレートのこのような問題を解決するために私が読んだもの(ここではSO)。(回答者は、これを有効にするためにメンバー関数をメンバー関数テンプレートに変更することがありました。)しかし、エラーは私にとっては変わりません。enable_ifリターンタイプに切り替える必要がありますか?

ああ、2つの要素タイプを比較できない場合、戻り型式はこの演算子を除外することになっています。それは実際に機能しますか?enable_ifあちこちに置くのも互換性がありますか?

4

1 に答える 1

11

興味深いことに、ここSOの特定の仲間が少し前にブログ投稿を書き、オーバーロードされた関数を簡単に許可する優れたC++11スタイルのSFINAE手法を示しました。テクニックと説明はここにあります

つまり、最初に解析されたときと非依存宣言が解決されたときの両方のテンプレートがタイプ的にまったく同じであるため、コードは失敗します。デフォルトの関数引数と同様に、デフォルトのテンプレート引数は、関数が実際に呼び出されたときにのみ置換されます。これは、宣言の時点でコンパイラーに両方のテンプレートがどのように見えるかです。

template<class T, unsigned Lt, class U, unsigned Lu, class Enable>
auto operator==(MyType<T,Lt> const& l, MyType<U,Lu> const& r);

次のコードはあなたが望むものを達成するはずです:

namespace detail{
enum class enabler{};
}

template<bool B, class T = detail::enabler>
using EnableIf = typename std::enable_if<B, T>::type;

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt < Lu)>...>
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt > Lu)>...>
auto  operator ==( MyType<T,Lt> const &l, MyType<U,Lu> const &r )
 -> decltype( std::declval<T>() == std::declval<U>() )
{ /*...*/ }

ただし、1つの質問が残っています...もしもどうなるでしょうかLt == Lu?その場合、どちらの過負荷も実行可能ではありません。

于 2012-06-02T12:45:55.310 に答える