Класс шаблона и ошибка «недопустимое использование неполного типа» - PullRequest
2 голосов
/ 24 октября 2019

У меня есть шаблон Matrix класса, и я использовал std::vector<std::vector<T>> для хранения данных. Мне нужно специализировать некоторые методы для std::complex матрицы, например:

template <typename T>
bool Matrix<T>::is_hermitian() const
{
   if (!(*this).is_squared())
      return false;
   for (int r = 0; r < rows_; r++)
      for (int c = 0; c < columns_; c++)
         if (mat[r][c] != mat[c][r])
            return false;
   return true;
}

Для специализированного метода я подумал что-то вроде этого:

template <typename T>
bool Matrix<std::complex<T> >::is_hermitian() const
{
   if (!(*this).is_squared())
      return false;
   for (int r = 0; r < rows_; r++)
      for (int c = 0; c < columns_; c++)
         if (mat[r][c] != std::conj(mat[c][r]))
            return false;
   return true;
}

Но компилятор возвращает мне ошибку

'invalid use of incomplete type' 

Я создал в конце файла .cpp группу классов, которые я мог бы использовать в основной программе:

template class Matrix<int>;
template class Matrix<double>;
template class Matrix<float>;
template class Matrix< std::complex<float> >;
template class Matrix< std::complex<int> >;

Как реализовать один метод дляall std::complex<T> type?

И если вы знаете, как заменить два последних экземпляра на Matrix< std::complex<T> >, я буду очень благодарен.

Ответы [ 2 ]

3 голосов
/ 24 октября 2019

Вы можете применить технику SFINE (т. Е. «Ошибка замещения не является ошибкой» ) вместе с перегрузкой функции, чтобы выбрать правильный метод, когда T равно std::complex в Matrix<T> в классе. 1006 *

Ниже приводится демонстрация идеи: ( См. Пример кода в режиме онлайн в режиме реального времени )

#include <type_traits>  // std::enable_if, std::false_type

// traits for checking, T is `std::complex`
template<typename> struct is_std_complex : std::false_type {};
template<typename T> struct is_std_complex<std::complex<T>> : std::true_type {};

// traits for `std::enable_if` helpers
template<typename Type, typename ReType = void>
using EnabledForComplex = typename std::enable_if<is_std_complex<Type>::value, ReType>::type;

template<typename Type, typename ReType = void>
using EnabledNotForComplex = typename std::enable_if<!is_std_complex<Type>::value, ReType>::type;

template<typename T>
class Matrix
{
   // ...members

public:    
   template<typename Type = T>
   auto is_hermitian() const -> EnabledNotForComplex<Type, bool>
   {
      // ... code for non-std::complex types
   }

   template<typename Type = T>
   auto is_hermitian() const->EnabledForComplex<Type, bool>
   {
      // ... code for std::complex types
   }
};

При этом, если выиметь доступ к , вы можете использовать if constexpr, который будет только создавать экземпляр ветви, что верно для случая во время компиляции. ( См. Пример кода онлайн в прямом эфире )

#include <type_traits> // std::false_type

// traits for checking, T is `std::complex`
template<typename> struct is_std_complex : std::false_type {};
template<typename T> struct is_std_complex<std::complex<T>> : std::true_type {};

template<typename T>
class Matrix
{
   // ...members

public:
   bool is_hermitian() const
   {
      if (!is_squared()) return false;
      if constexpr (is_std_complex<T>::value)
      {
         // ... code for std::complex types
      }
      else
      {
         // ... code for non-std::complex types
      }
      return true;
   }
};
2 голосов
/ 24 октября 2019

Вы не можете частично специализировать шаблоны функций, но вы можете использовать шаблоны классов. Одна хитрость заключается в том, чтобы делегировать функцию-член шаблону вспомогательного класса. Как то так:

template <typename T>
struct IsHermitianHelper;

template <typename T>
class Matrix {
  friend class IsHermitianHelper<T>;
public:
  bool is_hermitian() const;
};

template <typename T>
struct IsHermitianHelper {
  static bool is_hermitian(const Matrix<T>& m) {
    // General implementation here
  }
};

template <typename T>
struct IsHermitianHelper<std::complex<T>> {
  static bool is_hermitian(const Matrix<std::complex<T>>& m) {
    // Special case for std::complex here
  }
};

template <typename T>
bool Matrix<T>::is_hermitian() const {
  return IsHermitianHelper<T>::is_hermitian(*this);
}
...