I have a template Matrix
class and I used a std::vector<std::vector<T>>
to store data. I need to specialize some methods for std::complex
matrix, for example:
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;
}
For the specialized method I thought something like this:
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;
}
But the compiler returns me an error
'invalid use of incomplete type'
I instantiated at the end of the .cpp
file a bunch of class that I could be using in the main program:
template class Matrix<int>;
template class Matrix<double>;
template class Matrix<float>;
template class Matrix< std::complex<float> >;
template class Matrix< std::complex<int> >;
How can I implement one method for all std::complex<T>
type?
And if you know how to replace the last two instance with a Matrix< std::complex<T> >
sort of thing I will be very thankful.
You can apply SFINE(i.e."Substitution Failure Is Not An Error") technique along with function overloading to choose the correct method when T
is std::complex
in Matrix<T>
class instatiation.
Following is the demonstration of the idea: (See example code online live)
#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
}
};
That being said, if you have access to c++17, you could use if constexpr
, which will only instantiate the branch, which is true for the case at compile time. (See example code online live)
#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;
}
};
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments