Шаблоны классов неявного преобразования - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь реализовать класс Matrix с линейными алгебраическими операциями.Я хочу сделать класс доступным для нескольких типов значений, таких как uint, uchar, float, double.

. Заголовок выглядит следующим образом:

template<typename T>
class Matrix{
public:
    Matrix(int width, int height);
    Matrix(const Matrix<T> & other);
    virtual ~Matrix();
    unsigned int width() const { return width_; }
    unsigned int height() const { return height_; };
    T * data() const { return data_ptr_; };
private:
  T * data_ptr_;
  unsigned int width_;
  unsigned int height_;
}

Исходный файл выглядит следующим образом.

template<typename T>
Matrix<T>::Matrix(int width, int height ): width_(width), height_(height)
{
  data_ptr_ = new T[width * height];
}

template<typename T>
Matrix<T>::Matrix(const Matrix<T> & other): Matrix(other.width(), other.height() )
{
   memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T);
}

template<typename T>
Matrix<T>::~Matrix()
{
   delete []data_ptr_;
}

template class Matrix<double>;
template class Matrix<float>;
...

Теперь я хочу определить operator +, который будет возвращать Matrix типа, который обычное преобразование c ++ делает при добавлении двух значений, то есть

Matrix<double> + Matrix<float> => Matrix<double>
Matrix<int> + Matrix<float> => Matrix<float>

и я хочу сделать это без явных преобразований.Например,

Matrix<float> float_matrix(10,20);
Matrix<int> int_matrix(10,20);

auto sum_matrix = float_matrix + int_matrix;

, поэтому сумма должна иметь тип float.

Однако я попробовал 2 метода, но безуспешно.

Метод 1 Определите operator + как

//inside class definition
Matrix<T> operator+(const Matrix<T> &other) const;

и определите неявные конструкторы, такие как

//inside the class declaration
template<typename K>
Matrix(const Matrix<K> & other);

и создавать их только в очевидном иерархическом порядке: uchar-> uint->float->double, однако мне все еще приходится вручную приводить операнды различных типов.

Метод 2

Определите operator + как

//inside the class declaration
template<typename K, typename R>
Matrix<R> operator+(const Matrix<K> &other) const;

и напишите специализации для каждого случая, однако я не смог заставить компилятор правильно выводить аргументы шаблона.

Ни один из методов не кажетсячтобы быть правильным.

Кто-нибудь может указать мне направление?

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

Вариант метода 3 от MathanOliver: определить operator+() (не по теме: когда-либо определять operator+=() как метод и operator+() как внешнюю функцию) не как метод, а как внешнюю функцию (вы можете сделать его другом Matrix при необходимости).

template <typename T1, typename T2,
          typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
 { 
   // something useful
   return {m1.width(), m1.height()};
 }

Ниже приведен полный пример компиляции

#include <cstring>
#include <utility>

template <typename T>
class Matrix
 {
   public:
      Matrix(unsigned int width, unsigned int height)
         : width_(width), height_(height)
       { data_ptr_ = new T[width * height]; }

      Matrix(const Matrix<T> & other)
         : Matrix(other.width(), other.height() )
       { std::memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T)); }
      virtual ~Matrix()
       { delete []data_ptr_; }
      unsigned int width() const
       { return width_; }
      unsigned int height() const
       { return height_; };
      T * data() const
       { return data_ptr_; };
   private:
      T * data_ptr_;
      unsigned int width_;
      unsigned int height_;
 };

template <typename T1, typename T2,
          typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
 {
   return {m1.width(), m1.height()};
 }


int main ()
 {
   Matrix<int>   m1{1, 2};
   Matrix<float> m2{1, 2};

   auto m3 = m1 + m2;
   auto m4 = m2 + m1;

   static_assert( std::is_same<decltype(m3), Matrix<float>>{}, "!" );
   static_assert( std::is_same<decltype(m4), Matrix<float>>{}, "!" );

   return 0;
 }

Получение типа возвращаемой матрицы в виде default значение шаблона (Tr) Вы можете указать другой тип, если хотите, следующим образом

auto m5 = operator+<int, float, int>(m1, m2);

static_assert( std::is_same<decltype(m5), Matrix<int>>{}, "!" );
0 голосов
/ 04 июня 2018

Вы можете использовать метод 3 и использовать автоматическое вычитание типа C ++ 11, чтобы выяснить тип для вас.Использование

template<typename K>
auto operator+(const Matrix<K> &other) const -> Matrix<decltype(std::declval<T>() + std::declval<K>())>;

Это говорит о том, что возвращаемая матрица будет иметь тип того, что T, добавленное к K, будет.

Вы не сможете сделать пользовательскийправила с этим, но он будет следовать стандартным правилам повышения / конверсии.

...