Reputation:
I'm trying to make a simple matrix class
Relevant parts of "mymat.h"
#ifndef _MYMAT_H_GUARD_
#define _MYMAT_H_GUARD_
#include <iostream>
constexpr auto MYMAT_ERR_UNEXPECTED_TYPE = "Error, unexpected type!";
constexpr auto MYMAT_ERR_CODE_UNEXPECTED_TYPE = 0;
constexpr auto MYMAT_ERR_OUT_OF_BOUND = "Error, out of bound!";
constexpr auto MYMAT_ERR_CODE_OUT_OF_BOUND = 0;
template <typename T>
class MYMAT{
public:
T* data;
int x, y;
public:
MYMAT(int x, int y);
~MYMAT();
template <typename C>
void set(int x, int y, C val);
template<typename C>
bool checkType(C val) const;
void print_mat();
public:
T& operator ()(int x, int y);
private:
bool inRange(int x, int y);
};
#endif // !_MYMAT_H_GUARD_
template<typename T>
inline MYMAT<T>::MYMAT(int x, int y){
this->data = new T[x * y]();
this->x = x;
this->y = y;
}
template<typename T>
inline MYMAT<T>::~MYMAT(){
delete this->data;
}
template<typename T>
inline void MYMAT<T>::print_mat(){
int x, y;
for (y = 0; y < this->y; y++)
{
for (x = 0; x < this->x; x++)
{
std::cout << this->data[y * this->x + x] << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
}
template<typename T>
inline bool MYMAT<T>::inRange(int x, int y){
return !((x < 1) && (x > this->x) && (y < 1) && (y > this->y));
}
template<typename T>
template<typename C>
inline void MYMAT<T>::set(int x, int y, C val){
if (this->checkType(val)) {
if (this->inRange(x, y)) {
this->data[(y - 1) * this->x + (x - 1)] = val;
}
else {
std::cout << MYMAT_ERR_OUT_OF_BOUND;
exit(MYMAT_ERR_CODE_OUT_OF_BOUND);
}
}
else {
std::cout << MYMAT_ERR_UNEXPECTED_TYPE;
exit(MYMAT_ERR_CODE_UNEXPECTED_TYPE);
}
}
template<typename T>
inline T& MYMAT<T>::operator()(int x, int y)
{
return this->data[this->x * (y - 1) + (x - 1)];
}
template<typename T>
template<typename C>
inline bool MYMAT<T>::checkType(C val) const
{
return std::is_same_v<T, C>;
}
And below is how I call matrix and use set
method
#include <iostream>
#include "mymat.h"
int main()
{
MYMAT<int> m(3, 3);
m.set(2, 2, 500);
m.print_mat();
m.set(2, 2, 500.0);
m.print_mat();
}
It prints
0 0 0 0 500 0 0 0 0 Error, unexpected type!
But when call operator is used:
#include <iostream>
#include "mymat.h"
int main()
{
MYMAT<int> m(3, 3);
m(2, 2) = 500;
m.print_mat();
m(2, 2) = 500.0;
m.print_mat();
}
It prints:
0 0 0 0 500 0 0 0 0 0 0 0 0 500 0 0 0 0
As you see, the value is casted from double to int.
How can I apply the condition in set()
for call operator?
Upvotes: 1
Views: 76
Reputation: 60218
To achieve what you want:
m(2, 2) = 500.0; // do custom checks for conversions from
// right hand side to left hand side
returning a T&
from operator()
is not going to work, because you have no control over implicit conversions to T
. In this case, you can't prevent the conversion from double
to int
.
Instead, you can return a type from operator()
that you write yourself, so you have all the control you need over implicit conversions. This type needs to hold onto the information on the left hand side, which is the this
pointer of m
, and the arguments to operator()
. It only needs to support operator=
to check for implicit conversions from the right hand side:
private:
struct Wrapper
{
MYMAT *t; // holds onto the this pointer
int x, y;
template <typename C>
void operator=(C val)
{
t->set(x, y, val); // uses MYMAT::set to do the conversion checking
}
};
Now you can declare your operator()
like this:
public:
Wrapper operator ()(int x, int y);
and define it like this:
template<typename T>
inline auto MYMAT<T>::operator()(int x, int y) -> Wrapper
{
return {this, x, y};
}
Here's a demo.
Upvotes: 2