3

私は、整数型(short、int、long)と浮動小数点型(float、double)の両方をとるMatrixクラスに取り組んでいます。一部のメソッドを浮動小数点型(反転メソッドなど)のみに制限し、一部のメソッドに浮動小数点型と整数型(==演算子など)の実装を変えたいと思います。Boostの「enable_if」と「is_integral」/「is_floating_point」を使用するのが正しい方法だと思いますが、それを機能させることができないようです。

私の実装は、このc++セミ擬似コードに似ています。

template <typename T>
class Matrix
{
    ...
    bool operator==(Matrix<typename enable_if<is_integral<T> T >::type >) const;
    bool operator==(Matrix<typename enable_if<is_floating_point<T>::type T> >) const;
    typename enable_if<is_floating_point<T> T> computeInverse() const;
    ...
};
// implementation
bool Matrix<T>::operator==(Matrix<typename enable_if<is_integral<T> T >::type >) const {
  //implementation without precision
}
bool Matrix<T>::operator==(Matrix<typename enable_if<is_integral<T> T >::type >) const {
  //implementation using precision
}
Matrix<typename enable_if<is_floating_point<T> T>::type > Matrix<T>::computeInverse() const {
  //implementation requiring floating points
}

これは多くのコンパイルエラーを生成しますが、私はこれらが最も関連性のあるものだと思います:

error: no type named ‘type’ in ‘struct boost::enable_if<boost::is_integral<float>, float>’

error: no type named ‘type’ in ‘struct boost::enable_if<boost::is_floating_point<int>, int>’

これは、少なくともboostのenable_ifを使用しない限り、タイプごとに異なる実装を行うことができないことを示しています。これは正しいですか?

もしそうなら、どうすればこれを行うことができますか?テンプレートの特殊化が進むべき道であることは知っていますが、コードの重複が多すぎないようにしたいと思います。

4

2 に答える 2

2

最も簡単なのは、次の場所でオーバーロードされた関数を使用することですMatrix

template <typename T>
class Matrix
{
    template <bool isInteger> class Discrim;
    //  ...
    bool isEqual( Matrix const& other, Discrim<true> ) const
    {
        //  Integer implementation...
    }

    bool isEqual( Matrix const& other, Discrim<false> ) const
    {
        //  Floating point implementation...
    }

public:
    bool isEqual( Matrix const& other ) const
    {
        return isEqual( other, Discrim<std::numeric_limits<T>::is_integer>() );
    }
};

もちろん、あなたoperator==operator!=電話します。Matrix::isEqual

そうは言っても、コメントから判断するTと、浮動小数点型の場合は「ほぼ等しい」関数が必要です。これをしないでください。それは人々を混乱させるだけであり、将来的に問題を終わらせることはありません(== 推移的な操作ではなくなるため)。

于 2012-04-23T16:08:37.910 に答える
1

@DavidRodriguezのアドバイスに従って、クラスの一般的な機能を基本クラスに分けてみてください。次に、機能が異なる派生クラス全体の特殊化を提供します。それがより良いアプローチでしょう。

現在の実装を維持したい場合は、次のように、不要なバージョンのオペレーターを過負荷解決から除外することができます。

#include <iostream>
#include <type_traits>

template<class T>
struct Matrix
{
  // ...
};

template<class T>
typename std::enable_if<
    std::is_integral<T>::value, bool
  >::type
operator==( const Matrix<T>&, const Matrix<T>& )
{
  std::cout << "Integer version" << std::endl;
  return true;
}

template<class T>
typename std::enable_if<
    !std::is_integral<T>::value, bool
  >::type
operator==( const Matrix<T>&, const Matrix<T>& )
{
  std::cout << "Floating point version" << std::endl;
  return true;
}

int main()
{
  Matrix<int> m1, m2;
  Matrix<double> m3, m4;

  if( m1 == m2 ) {}

  if( m3 == m4 ) {}
}

演算子をメンバー関数として使用したい場合、それを機能させるために私が知っている唯一の方法は、ダミーのテンプレートパラメーターを演算子に追加&& std::is_same<T,U>し、std::enable_ifテスト条件に追加することです。

于 2012-04-23T16:10:23.920 に答える