Let me define a matrix class as follows
template<typename T, size_t rowSize, size_t colSize>
class Matrix
{
//Class implementation
};
Now if i've 2 matrices defined as
Matrix<double,3,2> A;
Matrix<double,2,5> B;
A*B;
Can the multiplication be done, If I try it would say no arguments can take the rhs as double,2,5 for *. Is it possible to generalise the template to multiply 'double,x,y' and 'double,y,z' and return a new matrix 'double,x,y'
template<typename T, size_t rowSize, size_t colSize>
class Matrix
{
// Implementation
};
template<
typename T,
typename U,
size_t rowSize1,
size_t commonSize,
size_t colSize2
>
auto operator * (Matrix<T, rowSize1,commonSize> const & a,
Matrix<U, commonSize,colSize2> const & b)
-> Matrix<decltype(std::declval<T>()*std::declval<U>()), rowSize1, colSize2>
{
// Implementation
}
int main()
{
Matrix<double,3,2> A;
Matrix<double,2,5> B;
auto C = A*B;
}
Or as member:
template<typename T, size_t rowSize, size_t colSize>
class Matrix
{
public:
template<typename U, size_t colSize2>
auto operator * (Matrix<U, colSize,colSize2> const & b)
-> Matrix<decltype(std::declval<T>()*std::declval<U>()), rowSize, colSize2>
{
// Implementation
}
};
It is possiple to overwrite the * operator within a class.
But then it would be generally
T& T::operator*(T otherMatrix);
{
//do multiplication by hand and return a new Matrix
}
and not taking just double as only type.
Related
I am currently writing a matrix class that will be able to support any number of rows and columns through templates. I'm stuck on how go about preventing an invalid operation (i.e. number of columns for matrix 1 ≠ number of rows for matrix 2). I could of course store the number of rows and columns and check at run time, but optimally I'd like to make this check at compile time through a "wildcard" template argument.
In other words...
I want to do this:
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
void operator *=(const mat<T, C, [can be anything]> &other) {
/* do operation */
}
};
Instead of this:
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
int rows = R;
int columns = C;
void operator *=(const mat *other) {
if (columns != other->rows) {
/* error */
} else {
/* do operation */
}
}
};
Is this possible? If so, how do I do it?
This works for me
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
template <int CC>
void operator *=(const mat<T, C, CC> &other) {
/* do operation */
}
};
int main()
{
mat<int, 2, 3> m1;
mat<int, 3, 4> m2;
m1 *= m2;
}
Define template《int K》mat《T,R,K》& operator*(const mat《T, C,K》& other)..
I want to design a m x n matrix class (as a template parameterized by m rows and n columns) and need to specialize it in order to equip it with operations that are mathematically possible based on three conditions:
m > n
m == n
no specialization for m < n, that is, basic or default implementation
The template signature is simply:
template <size_t m, size_t n, typename T = double> class MatrixBase
{
....
};
How do I do that? Can it be done with type traits? Or should I use std::conditional<> or std::enable_if<> ?. Conceptually, what I want to accomplish is to add methods to a class but without subclassing it and creating any inheritance hierarchy. The derivation tree I want to use for other things, namely the data storage within the matrix.
So I would like to have a matrix that if declared as for instance MatrixBase<4, 4, float> has (by virtue of specialization) a method called inverse (), while matrices declared with m <> n don't. Similarly, extra methods for matrices with m > n.
It can be done with std::enable_if:
template <size_t m, size_t n, typename T = double>
class MatrixBase
{
public:
template <typename T1 = T>
std::enable_if_t<m == n, MatrixBase<m, m, T1>> inverse() const
{
// Calculate inverse
return{};
}
};
int main(int argc, const char *argv[])
{
auto msquare = MatrixBase<4, 4>();
auto mrect = MatrixBase<4, 3>();
msquare.inverse(); // No error
mrect.inverse(); // Compilation error
return 0;
}
For partial specialization you can also use enable_if:
template <size_t m, size_t n, typename T = double, typename E = void>
class MatrixBase
{
public:
template <typename T1 = T>
std::enable_if_t<m == n, MatrixBase<m, m, T1>> inverse() const
{
// Calculate inverse
return{};
}
};
template <size_t m, size_t n, typename T>
class MatrixBase<m, n, T, std::enable_if_t<m == n, void>>
{
public:
static bool m_equals_n()
{
return true;
}
};
template <size_t m, size_t n, typename T>
class MatrixBase<m, n, T, std::enable_if_t<n < m, void>>
{
public:
static bool m_greater_than_n()
{
return true;
}
};
template <size_t m, size_t n, typename T>
class MatrixBase < m, n, T, std::enable_if_t<m < n, void>>
{
public:
static bool m_less_than_n()
{
return true;
}
};
int main(int argc, const char *argv[])
{
auto msquare = MatrixBase<4, 4>();
auto m_4_3 = MatrixBase<4, 3>();
auto m_3_4 = MatrixBase<3, 4>();
msquare.m_equals_n();
//msquare.m_greater_than_n(); // Compilation error
m_4_3.m_greater_than_n();
m_3_4.m_less_than_n();
return 0;
}
I have a Matrix class template as follows:
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
What I want is to define a .setIdentity() function only for instantiations when nrows==ncols is true at compile time. And there will be no definition of .setIdentity() when nrows==ncols is false.
What I am trying is using enable_if idiom, but that will define the function for all cases. Isn't it?
You can do it with std::enable_if in the following mode
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{ /* do something */ }
A full example
#include <type_traits>
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{ return data[i][j]; }
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{ /* do something */ }
};
int main()
{
Matrix<int, 3, 3> mi3;
Matrix<int, 3, 2> mnoi;
mi3.setIdentity();
// mnoi.setIdentity(); error
return 0;
}
--- EDIT ---
As pointed in a comment by Niall (regarding the TemplateRex's answer, but my solution suffer from the same defect) this solution can be circonvented expliciting the number of rows and columns in this way
mi3.setIdentity<4, 4>();
(but this isn't a real problem (IMHO) because mi3 is a square matrix and setIdentity() could work with real dimensions (nrows and ncols)) or even with
mnoi.setIdentity<4, 4>()
(and this is a big problem (IMHO) because mnoi isn't a square matrix).
Obviously there is the solution proposed by Niall (add a static_assert; something like
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if<r == c>::type setIdentity ()
{
static_assert(r == nrows && c == ncols, "no square matrix");
/* do something else */
}
or something similar) but I propose to add the same check in std::enable_if.
I mean
template <std::size_t r = nrows, std::size_t c = ncols>
typename std::enable_if< (r == c)
&& (r == nrows)
&& (c == ncols)>::type setIdentity ()
{ /* do something */ }
The lazy and needlessly repetitive way
Just add a partial specialization:
template<typename T, std::size_t N>
class Matrix<T, N, N>
{
T data[N][N];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
void setidentity(/*whatever params*/) { std::cout << "yay!"; }
};
Live Example
For general N * M matrices, the general template will be instantiated, whereas only for N * N matrics, this specialization is a better match.
Disadvantage: code repetition of all regular code. Could use a base class, but it's actually easier to do some SFINAE magic (below)
A slightly harder but more economical way
You can also use SFINAE by adding hidden template parameters N and M that default to nrows and ncols to setidentity, and to enable_if on the condition N == M.
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
template <std::size_t N = nrows, std::size_t M = ncols, std::enable_if_t<(N == M)>* = nullptr>
void setidentity(/*whatever params*/) {
static_assert(N == nrows && M == ncols, "invalid");
std::cout << "yay!";
}
};
Or, since the question was tagged C++11, use typename std::enable_if<(N == M)>::type instead.
Live Example
Use a pseudo-CRTP to add modular support for something.
template<class T, std::size_t nrows, std::size_t ncols>
class Matrix;
template<class T, std::size_t size>
struct MatrixDiagonalSupport {
auto self() { return static_cast<Matrix<T, size, size>*>(this); }
auto self() const { return static_cast<Matrix<T, size, size> const*>(this); }
void setIdentity() {
for (std::size_t i = 0; i < size; ++i) {
for (std::size_t j = 0; j < i; ++j) {
(*self())(i,j) = {};
}
(*self())(i,i) = 1; // hope T supports this!
for (std::size_t j = i+1; j < size; ++j) {
(*self())(i,j) = {};
}
}
}
};
template<class T>
struct empty_t {};
template<bool b, class T>
using maybe= std::conditional_t<b, T, empty_t<T>>;
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix: public maybe<nrows==ncols,MatrixDiagonalSupport<T, nrows>>
{
// ...
Here we inherit from nothing if we aren't diagonal, and a class implementing set identity if we are diagonal.
Users of Matrix get .setIdentity() from its parent magically if it is right.
static_cast inside self() ends up being a zero-cost abstraction and giving the base class access to the child class.
This is pseudo-CRTP because we don't actually pass the derived class type to the parent, just enough information for the parent to reconstruct it.
This solution makes the method an actual method, and avoids any kind of SFINAE trickery.
Live example
In C++11 replace conditional_t<?> with typename conditional<?>::type:
template<bool b, class T>
using maybe=typename std::conditional<b, T, empty_t<T>>::type;
and everything should compile.
A basic, but simple solution not mentioned by any other answer: you can use std::conditional and inheritance.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
struct HasSetIdentity {
void setIdentity() { }
};
struct HasNotSetIdentity {};
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix: public std::conditional<(nrows==ncols), HasSetIdentity, HasNotSetIdentity>::type
{
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
int main() {
Matrix<int, 2,2> m1;
m1.setIdentity();
Matrix<int, 2,3> m2;
// Method not available
// m2.setIdentity();
}
You can still move data down the hierarchy if you need them to be shared by all the subobjects.
It mostly depends on the real problem.
skypjack and max66 have both presented simple answers to the problem. This is just an alternate way of doing it, using simple inheritance, although it means the use of a child class for square matrices:
template<typename T, std::size_t nrows, std::size_t ncols>
class Matrix
{
protected:
T data[nrows][ncols];
public:
T& operator ()(std::size_t i, std::size_t j)
{
return data[i][j];
}
};
template<typename T, std::size_t N>
class SqMatrix : public Matrix <T, N, N>
{
public:
setIdentity()
{
//Do whatever
}
}
In my C++ code I have a Matrix class, and some operators written to multiply them. My class is templated which mean I can have int, float, double ... matrices.
My operator overload is classic I guess
template <typename T, typename U>
Matrix<T>& operator*(const Matrix<T>& a, const Matrix<U>& b)
{
assert(a.rows() == b.cols() && "You have to multiply a MxN matrix with a NxP one to get a MxP matrix\n");
Matrix<T> *c = new Matrix<T>(a.rows(), b.cols());
for (int ci=0 ; ci<c->rows() ; ++ci)
{
for (int cj=0 ; cj<c->cols() ; ++cj)
{
c->at(ci,cj)=0;
for (int k=0 ; k<a.cols() ; ++k)
{
c->at(ci,cj) += (T)(a.at(ci,k)*b.at(k,cj));
}
}
}
return *c;
}
In this code I return a matrix of the same type than the first parameter i.e. Matrix<int> * Matrix<float> = Matrix<int>. My question is how can I detect the most precised type among the two I give to not lose too much precision i.e. to have Matrix<int> * Matrix<float> = Matrix<float> ? Is there a clever to do it ?
What you want is just the type that happens when you multiply a T by a U. That can be given by:
template <class T, class U>
using product_type = decltype(std::declval<T>() * std::declval<U>());
You can just use that as an extra defaulted template parameter:
template <typename T, typename U, typename R = product_type<T, U>>
Matrix<R> operator*(const Matrix<T>& a, const Matrix<U>& b) {
...
}
In C++03 you can accomplish the same thing by doing a giant series of overloads with lots of small helper types like so (this is how Boost does it):
template <int I> struct arith;
template <int I, typename T> struct arith_helper {
typedef T type;
typedef char (&result_type)[I];
};
template <> struct arith<1> : arith_helper<1, bool> { };
template <> struct arith<2> : arith_helper<2, bool> { };
template <> struct arith<3> : arith_helper<3, signed char> { };
template <> struct arith<4> : arith_helper<4, short> { };
// ... lots more
We then can write:
template <class T, class U>
class common_type {
private:
static arith<1>::result_type select(arith<1>::type );
static arith<2>::result_type select(arith<2>::type );
static arith<3>::result_type select(arith<3>::type );
// ...
static bool cond();
public:
typedef typename arith<sizeof(select(cond() ? T() : U() ))>::type type;
};
Assuming you write out all the integer types, then you can use typename common_type<T, U>::type where before I used product_type.
If this isn't a demonstration of how cool C++11 is, I don't know what is.
Note, operator* should not return a reference. What you're doing will leak memory.
I'm trying to get familiar with C++ templates. I need to write a template of function that concatenates 2 arrays:
template<typename T, int Size>
class Array
{
public:
void push(int i, const T& t) { _elem[i] = t; }
private:
T _elem[Size];
};
For example I have 2 arrays:
Array<int,3> a1;
Array<int,4> a2;
I don't know how to write this function, that will return
Array<int,7>.
How should header of this function look like?
You should try it like this:
template<typename T, int A, int B>
Array<T, A+B> concatenate(Array<T, A> first, Array<T, B> second)
{
Array<T, A+B> result;
for (int idx = 0; idx < A; ++idx) {
result.push(idx, first[idx]);
}
for (int idx = 0; idx < B; ++idx) {
result.push(idx+A, second[idx]);
}
return result;
}
You could do it like this, as a free-function outside the class:
template <typename T, int SizeA, int SizeB>
Array<T, SizeA + SizeB> join(const Array<T, SizeA>& first,
const Array<T, SizeB>& second)
{
/* ... */
}
For what it's worth, you should probably use std::size_t from <cstddef> instead of int.