3

我正在研究一个 Matrix 类,它同时采用整数(short、int、long)和浮点类型(float、double)。我希望某些方法仅限于浮点类型(例如反转方法),并且某些方法对浮点类型和整数类型具有不同的实现(例如 == 运算符)。我有一种预感,正确的方法是使用 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 的建议,并将您的类的通用功能分离到一个基类中;然后提供功能不同的整个派生类的特化。那将是更好的方法。

如果您确实想保留当前的实现,您可以 SFINAE 将不需要的运算符版本排除在重载决议之外,如下所示:

#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 回答