How To Allow Wildcard Template Argument - c++

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)..

Related

Passing templated-function by reference in recursive template

In my PhD, I very often use matrices of various dimensions and data types. For first time, I use recursive templates in C++11 for manipulating my non-contiguous arrays, so it is the last time I see calloc and free. With the help of stackoverflow link1 and link2 I achieved my initial goal of de&allocating them. Greedy me, I now want my class to perform the basic cellwise operations e.i. addition, division. It works fine if I use enum to determine which operation is performed, but I fail to use reference to an other templated function that performs the operation.
The main:
//Define the size of each dimension in a vector
int height = 3, width = 2;
std::vector<int> dimensions;
dimensions.push_back(height);
dimensions.push_back(width);
// Allocate a table of doubles 3x2
smatrix<double **> dbltbl(dimensions);
// Assign values in the cells
for (int r = 0; r < height; ++r)
for (int c = 0; c < width; ++c) {
dbltbl.uacc()[r][c] = (r * width + c) * 2.6;
}
// Create a table of ints from the table of doubles (rounded copy)
smatrix<int **> inttbl = dbltbl;
// Add cell-wise the table of ints to the table of doubles
dbltbl.cellwise_add(inttbl);
The enum way
The enum:
enum clc_op { addition, subtration, multiplication, division };
The operation function:
template <typename S, typename T>
T add(S one, T two) {
return one + two;
}
The recursive template solution:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, enum clc_op operation) {
switch (operation) {
case clc_op::addition:
dest = add(src, dest);
break;
//…
//...
}
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, enum clc_op operation) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation)
}
}
The class method (e.g. P = double** and U=int**):
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, clc_op::addition);
}
The output:
==========================================
Table of doubles:
0 2.6
5.2 7.8
10.4 13
==========================================
Table of ints from the table of doubles:
0 2
5 7
10 13
==========================================
Table of doubles+ints:
0 4.6
10.2 14.8
20.4 26
This solution doesn’t look elegant, making me believe it is the wrong approach. So, I try to pass the operation as reference to function, and I fail hard time.
The function by reference way:
The addition (operation) function remains the same. The recursive solution:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, T (*operation)(S, T)) {
dest = operation(src, dest);
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, T (*operation)(S, T)) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
The class method:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, add<U, P>);
}
The error:
./sm_example/smatrix.hpp:305:17: required from ‘void smatrix<P>::cellwise_add(const smatrix<U>&) [with U = int**; P = double**]’
./sm_example/sm_example.cpp:157:35: required from here
./sm_example/smatrix.hpp:159:19: error: invalid operands of types ‘double**’ and ‘double**’ to binary ‘operator+’
return (T)one + two;
I understand that addition between pointers is not allowed, although I know it will not happen the compiler doesn't. I have no clue how I could work around it. How do I pass the operation’s template-function (add) by reference in the recursive template-function? Do I use templates in a wrong way?
I do not want to use std::vector for the time being, but comments are welcome. Worst case scenario, my dataset reaches 100MBytes in 5 dimensions.
Solution in C++11 thx to #Yakk below
The operation function:
struct add {
template <typename S, typename T>
S operator()(S &x, T &y) { return x + y; }
};
The rock bottom of recursive template solution:
template <typename S, typename T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op &&operation) {
dest = operation(dest, src);
return;
}
The class method:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
cellwise_ops(addend.uacc(), _full, _dim, add());
}
If you made it so far, thank you!
Chris
Don't use function pointers.
template <typename S, typename T>
T add(S one, T two) {
return (T)one + two;
}
const auto do_add=[](auto&&...args)->decltype(auto) {
return add( decltype(args)(args)... );
};
or
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define DO_FUNC(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
const auto do_add=DO_FUNC(add);
in both of these cases, we have a single object do_add that represents adding things. This can also be written manually as a struct with an operator() if you care.
do_add isn't a function pointer.
template <class S, class T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op&& operation)
{
dest = operation(src, dest);
}
template <class S, class T, class Op>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, Op&& operation)
{
if (dims.size() == 0)
return false;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
and we are done.

declaring a template method for a template class

I'm trying to declare a template method on a template class and it's not working for me.
It's better to explain by giving the code so here it is:
I have this class:
matrix.h
template <class T,int a,int b>
class Matrix {
private:
int x;
int y;
public:
class IllegalOperation();
template<T,int c,int d>
Matrix<T,a,b> operator+(const Matrix<T,c,d> m);
//...
}
matrix.cpp
template<class T,int a,int b>
template<T,int c,int d>
Matrix<T,a,b> Matrix<T,a,b>::operator+(const Matrix<T,c,d> m){
if(a!=c || b!=d) throw IllegalOperation();
// add matrices and return the result
}
I'd like this code to work for any 2 types of Matrix and Matrix where a,b,c and d can be different.
for example, I want this code to compile and return an error (in run time):
const Matrix<int, 3, 2> m1;
const Matrix<int, 7, 3> m2;
// init m1 and m2
m1+m2;
While this code should compile and run successfully:
const Matrix<int, 3, 2> m1;
const Matrix<int, 3, 2> m2;
// init m1 and m2
m1+m2;
However, when I try to compile the code above I get this error:
no match for âoperator+ in m1+m2
Change your code to this (not considering the things that I think might be wrong here, only changed it to make it compile)
#include <type_traits>
template <typename T,int a,int b>
class Matrix {
public:
template<typename T2, int c, int d>
Matrix<T,a,b> operator+(const Matrix<T2, c, d>& m) const;
private:
int x;
int y;
};
template <typename T,int a,int b>
template <typename T2, int c, int d>
Matrix<T, a, b> Matrix<T, a, b>::operator+(const Matrix<T2, c, d>&) const {
if(a != c || b != d) {
throw IllegalOperation{};
}
/*constexpr*/ if (!std::is_same<T, T2>::value) {
throw Error{};
}
return *this;
}
int main() {
const Matrix<int, 3, 2> m1{};
const Matrix<int, 7, 3> m2{};
m1 + m2;
return 0;
}
I've made a few changes here
The operator+ is const, you were trying to call a non const member function on a const object, would not work
The matrix parameter in the addition operator is now taken by reference
The operator+ cannot be defined in the .cpp file as mentioned in the comments, it must go in the header file (if you want to split up the interface and implementation, the best you can do is In the C++ Boost libraries, why is there a ".ipp" extension on some header files)
I usually like having the public section first since it gives the reader a better idea about the interface of the class.

How to partially specialize a template based on the relation between its two integer parameters

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;
}

Is the matrix multiplication possible with template arguments

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.

C++ Matrix multiplication type detection

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.