【问题标题】:How to change a template method based on whether the type is an integral or floating point type?如何根据类型是整数类型还是浮点类型来更改模板方法?
【发布时间】:2012-04-23 15:32:19
【问题描述】:

我正在研究一个 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,这样对吗?

如果是这样,我该怎么做?我知道模板专业化是一种方法,但我想避免重复太多代码。

【问题讨论】:

  • 我会尝试考虑是否可以将矩阵分解为公共部分(移动到基本类型)和整个矩阵类的两个特化,用于两种不同类型,而不是混合实现一个模板。

标签: c++ templates boost enable-if


【解决方案1】:

最简单的方法是在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, of 当然。

话虽如此:从你的 cmets 来看,你想要一个“几乎相等” 如果T 是浮点类型,则函数。不要这样做。它只会 迷惑人们,并在路上造成无穷无尽的问题(因为== 将不再是传递操作)。

【讨论】:

  • 感谢您对“几乎相等”功能的回答和提醒。当我找到解决当前问题的方法时,我会为此寻找不同的解决方案。
【解决方案2】:

您应该尝试遵循@DavidRodriguez's advice 并将您的类的通用功能分离到一个基类中;然后提供功能不同的整个派生类的特化。那将是更好的方法。

如果您确实想保留当前的实现,您可以 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 ) {}
}

如果您希望运算符作为成员函数,我所知道的使其工作的唯一方法是向运算符添加一个虚拟模板参数并将&amp;&amp; std::is_same&lt;T,U&gt; 添加到std::enable_if 测试条件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多