Subscript (" [ ] ")operator gives strange errors - c++

I am getting some strange behaviour from visual studio, regarding the following code snippet, The error list shows several instances of E0349: no operator"[]" matches these operands.
Intellisense seems to be implying a type mismatch, but as you will see in the code, there is no type mismatch.
To begin, I have defined a Vec4 struct for the purposes of making a mat4:
(I have only included the pertinent functions)
struct Vec4f
{
union
{
struct { float x, y, z, w; };
struct { float r, g, b, a; };
};
// copy constructor
Vec4f(Vec4f const & v) :
x(v.x),
y(v.y),
z(v.z),
w(v.w)
{
}
// Operators
float & operator[](int index)
{
assert(index > -1 && index < 4);
return (&x)[index];
}
Vec4f & operator=(Vec4f const & v)
{
// If I use: "this->x = v[0];" as above, E0349
this->x = v.x;
this->y = v.y;
this->z = v.z;
this->w = v.w;
return *this;
}
}
Using the above Vec4 class, I have created a 4x4 matrix:
struct Mat4f
{
//storage for matrix values
Vec4f value[4];
//copy constructor
Mat4f(const Mat4f& m)
{
value[0] = m[0]; // calling m[0] causes E0349
value[1] = m[1];
value[2] = m[2];
value[2] = m[3];
}
inline Vec4f & operator[](const int index)
{
assert(index > -1 && index < 4);
return this->value[index];
}
}
When any of the "[]" operators are called, I end up with this E0349 error, and I do not understand the problem. Oddly, the file compiles just fine. I have tried deleting the hidden ".suo" file as suggested in an answer to a different question, but to no avail. I would appreciate this explained to me.

Mat4f::operator[] is a non-const member function, which can't be called on the argument m of Mat4f::Mat4f, it's declared as const & Mat4f.
You could add another const overloading, which could be called on constants. e.g.
inline Vec4f const & operator[](const int index) const
// ~~~~~ ~~~~~
{
assert(-1 < index && index < 4); // As #Someprogrammerdude commented, assert(-1 < index < 4) doesn't do what you expect
return this->value[index];
}

Related

Conversion from class to identical class with different template types

I have the simple class "vec2". I would like this class to be able to store doubles and double references in the class template, or even int and int references. Here is the desired behavior-
vec2<double> base(5, 5); //normal vec2
vec2<double&> reference(base.x, base.y); //vec2 reference to vec2 "base"
vec2<double> third;
base.x++; //base.x equals 6, this also changes reference.x to 6;
third = reference; //conversion between vec2<double> and vec2<double&>
I would also like modifying a reference instance of vec2 to be impossible, except by changing the variables it is referencing- so the following code would give a compiler error
vec2<double&> reference(base.x, base.y); //vec2 reference to vec2 "base"
reference.x = 5; //undesired behaviour
Is there a way to make the members x and y public when dealing with non-reference class types, but private when the class type is a reference? This would require methods specific to when it is a reference that will return the values of x and y. In the reference version it would also need to not have the overloaded operator methods that can affect the references. I slightly understand template specialization, but not enough to actually implement it.
Anyways, the main point of this is to find out how to take a class of type vec2<double>, and convert it to a class of type vec2<double&>.
Or, conversely, take a class of type vec2<double&>, and convert it to a class of type vec2<double>.
Here is my simple vec2 class-
template <class T> class vec2{
public:
vec2(){
x = 0;
y = 0;
}
vec2(T X, T Y){
x = X;
y = Y;
}
void normalize(){ //this function should inaccesable to any "reference version" of vec2
*this /= magnitude();
}
void rotate(double radians, vec2 center){ //this should also be inaccesable to reference versions
vec2 ogPts = *this -= center;
x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
*this += center;
}
double magnitude() const{
return sqrt(x * x + y * y); //this should be available to both
}
T x;
T y;
vec2 operator+(const vec2 &v) const{ //available to both
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{ //available to both
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{ //available to both
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
return vec2(x*v, y*v);
}
vec2 operator/(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
return vec2(x/v, y/v);
}
vec2 operator+=(const vec2 &v){ //inaccesable to reference versions of the class
x += v.x;
y += v.y;
return *this;
}
vec2 operator-=(const vec2 &v){ //inaccesable to reference versions
x -= v.x;
y -= v.y;
return *this;
}
vec2 operator*=(const vec2 &v){ //inaccesable to reference versions
x *= v.x;
y *= v.y;
return *this;
}
vec2 operator*=(T v){ //inaccesable to reference versions
x *= v;
y *= v;
return *this;
}
vec2 operator/=(T v){ //inaccesable to reference versions
x /= v;
y /= v;
return *this;
}
bool operator==(const vec2 &v) const{ //this should be available to both
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{ //this should be available to both
return (v.x != x || v.y != y);
}
};
Any help is much appreciated! I haven't worked with templates much, in fact, I just started yesterday! Thanks in advance for your time!
I did a bit more research, and managed to learn a lot on template specialization. Here is the functioning vec2 class which implements everything I wanted, plus a "perpindiculate" function and a "swap" function-
template <class T> class vec2{
public:
vec2(){
x = 0;
y = 0;
}
vec2(T X, T Y){
x = X;
y = Y;
}
operator vec2<T&>(){
return vec2<T&>(x, y);
}
void swap(){
std::swap(x, y);
}
void perpindiculate(){
std::swap(x, y);
y = -y;
}
void normalize(){
*this /= magnitude();
}
void rotate(double radians, vec2 center){
vec2 ogPts = *this -= center;
x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
*this += center;
}
double magnitude() const{
return sqrt(x * x + y * y);
}
vec2 operator+(const vec2 &v) const{
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T v) const{
return vec2(x*v, y*v);
}
vec2 operator/(T v) const{
return vec2(x/v, y/v);
}
vec2 operator+=(const vec2 &v){
x += v.x;
y += v.y;
return *this;
}
vec2 operator-=(const vec2 &v){
x -= v.x;
y -= v.y;
return *this;
}
vec2 operator*=(const vec2 &v){
x *= v.x;
y *= v.y;
return *this;
}
vec2 operator*=(T v){
x *= v;
y *= v;
return *this;
}
vec2 operator/=(T v){
x /= v;
y /= v;
return *this;
}
bool operator==(const vec2 &v) const{
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{
return (v.x != x || v.y != y);
}
T x;
T y;
};
template<class T>
class vec2<T&>{
public:
vec2(T& X, T& Y) : x{X}, y{Y} {}
operator vec2<T>(){
return vec2<T>(x, y);
}
vec2<T> swap() const{
return vec2<T>(y, x);
}
vec2<T> perpindiculate() const{
return vec2<T>(-y, x);
}
vec2<T> normalize() const{
return *this / magnitude();
}
vec2<T> rotate(double radians, vec2 center) const{
return vec2<T>(x*cos(radians) - y*sin(radians), y*cos(radians) + x*sin(radians));
}
double magnitude() const{
return sqrt(x * x + y * y);
}
vec2 operator+(const vec2 &v) const{
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T& v) const{
return vec2(x*v, y*v);
}
vec2 operator/(T& v) const{
return vec2(x/v, y/v);
}
bool operator==(const vec2 &v) const{
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{
return (v.x != x || v.y != y);
}
T getx(){
return x;
}
T gety(){
return y;
}
private:
T& x;
T& y;
};
Here is an example of it working-
double x = 5; //create future reference variables
double y = 3;
vec2<double&> vecref(x, y); //create vec2 referring to x and y
x = 7; //change x and y values, also changing vecref's values as well
y = 8;
vec2<double> vecOffRef = vecref; //conversion from a reference vec to a normal one
vec2<double&> vecOffRefref = vecOffRef; //conversion from a normal vec to a reference one
vecOffRef.normalize(); //normalize vec, also normalizing vecOffRefref
/* x equals 7, y = 8
vecRef equals (7, 8)
vecOffRef equals (0.6585, .7525)
vecOffRefRef equals (0.6585, .7525) */
A simplified version. By making the fields private, they can't be modified. I didn't try implementing all the operator= methods, but your code should work.
I'm not quite sure where your confusion is. A scan didn't see any problems, except I'd make the fields private so no one can touch them, and add accessor methods instead.
#include <iostream>
using namespace std;
template <class T>
class MyClass {
private:
T x;
T y;
public:
MyClass(T _x, T _y) : x(_x), y(_y) {}
T getX() const { return x; }
T getY() const { return y; }
};
int main(int, char **) {
double x {1.0};
double y {2.5};
MyClass<double> withDouble(x, y);
MyClass<double &> withRef{x, y};
cout << "withDouble: " << withDouble.getX() << ", " << withDouble.getY() << endl;
cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;
x = 3.9;
y = 5.4;
cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;
}

No matching operator for operands Matrix2D and Matrix2D (but I have defined them)

I'm coding a small library to make operations with matrices and vectors and I have ran into a problem a bit strange.
I have overloaded my *, + and - operators to be able to easily operate with my Matrix2D objects.
typedef float MVT; // MatrixValueType
class Matrix2D {
private:
int rows, columns;
MVT** values;
int largestNumberToPrint;
public:
Matrix2D(const int _rows, const int _columns);
Matrix2D(const std::vector<std::vector<MVT>> _matrixValues);
~Matrix2D();
Matrix2D t();
MVT get(int _row, int _column);
void set(int _row, int _column, MVT& _value);
void print();
}
That's basically my Matrix2D class, and this is how I have overloaded my * operator:
friend linear::Matrix2D operator*(const linear::Matrix2D& a, const linear::Matrix2D& b) {
if(a.columns != b.rows)
throw std::logic_error("columns of A must match rows of B");
if(a.rows < 1)
throw std::logic_error("rows of A is 0, no possible multiplication");
linear::Matrix2D _multMatrix(a.rows, b.columns);
for(auto _row = 0; _row < _multMatrix.rows; _row++)
for(auto _col = 0; _col < _multMatrix.columns; _col++) {
MVT _mulValue = 0;
for(auto _trace = 0; _trace < a.columns; _trace++)
_mulValue += a.values[_row][_trace] * b.values[_trace][_col];
_multMatrix.set(_row, _col, _mulValue);
}
return _multMatrix;
}
And here the + operator (The - operator is the same but with - operations)
friend linear::Matrix2D operator+(const linear::Matrix2D& a, const linear::Matrix2D& b) {
if(a.columns != b.columns || a.rows != b.rows)
throw std::logic_error("A and B must be same size");
if(a.rows < 1 || b.rows < 1)
throw std::logic_error("rows of A and B can't be empty");
linear::Matrix2D _sumMatrix(a.rows, a.columns);
for(auto _row = 0; _row < _sumMatrix.rows; _row++)
for(auto _col = 0; _col < _sumMatrix.columns; _col++) {
MVT _mulValue = a.values[_row][_col] + b.values[_row][_col];
_sumMatrix.set(_row, _col, _mulValue);
}
return _sumMatrix;
}
I have tested that the overloaded operator works and it does. The problem comes now, I have overloaded to the operator *=, and to avoid having to rewrite too much code I have done this:
linear::Matrix2D& operator*=(const linear::Matrix2D& _a){
*this = *this * _a;
return *this;
}
But I got an error in this line '*this = *this * _a;' on the * multiplication operator. "It says no operator '*' matches these operands -- operand types are: linear::Matrix2D * const linear::Matrix2D", but as I've showed you I have defined them.
And the same happens for += and -= operators:
linear::Matrix2D& operator+=(const linear::Matrix2D& _a){
*this = *this + _a;
return *this;
}
And
linear::Matrix2D& operator-=(const linear::Matrix2D& _a){
*this = *this - _a;
return *this;
}
The errors are:
"It says no operator '+' matches these operands -- operand types are: linear::Matrix2D + const linear::Matrix2D"
And
"It says no operator '-' matches these operands -- operand types are: linear::Matrix2D - const linear::Matrix2D"
capture of error log in vscode
Finally, I have to say that even that vscode shows up this error, I can compile and run this code with mingw g++, but I'm not sure why this compiles and runs if there's an error or if internally something is going wrong while running it.
I would appreciate any help, thanks.

How to implement a tensor class for Kronecker-Produkt [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Currently I came across an interesting article what's called the Kronecker-Produkt. At the same time I'm working on my neural network library.
So that my algorithm works, I need a tensor class, where I can get the product of two tensor's with an overloaded * operator.
Consider the following example/questions:
How to efficiently construct/store the nested matrices?
How to perform the product of two tensor's?
How to visualize tensor c as simply as possible?
My class 3 tensor which currently only supports 3 dimensions:
#pragma once
#include <iostream>
#include <sstream>
#include <random>
#include <cmath>
#include <iomanip>
template<typename T>
class tensor {
public:
const unsigned int x, y, z, s;
tensor(unsigned int x, unsigned int y, unsigned int z, T val) : x(x), y(y), z(z), s(x * y * z) {
p_data = new T[s];
for (unsigned int i = 0; i < s; i++) p_data[i] = val;
}
tensor(const tensor<T> & other) : x(other.x), y(other.y), z(other.z), s(other.s) {
p_data = new T[s];
memcpy(p_data, other.get_data(), s * sizeof(T));
}
~tensor() {
delete[] p_data;
p_data = nullptr;
}
T * get_data() {
return p_data;
}
static tensor<T> * random(unsigned int x, unsigned int y, unsigned int z, T val, T min, T max) {
tensor<T> * p_tensor = new tensor<T>(x, y, z, val);
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<T> dist(min, max);
for (unsigned int i = 0; i < p_tensor->s; i++) {
T rnd = dist(mt);
while (abs(rnd) < 0.001) rnd = dist(mt);
p_tensor->get_data()[i] = rnd;
}
return p_tensor;
}
static tensor<T> * from(std::vector<T> * p_data, T val) {
tensor<T> * p_tensor = new tensor<T>(p_data->size(), 1, 1, val);
for (unsigned int i = 0; i < p_tensor->get_x(); i++) p_tensor->set_data(i + 0 * p_tensor->get_x() * + 0 * p_tensor->get_x() * p_tensor->get_y(), p_data->at(i));
return p_tensor;
}
friend std::ostream & operator <<(std::ostream & stream, tensor<T> & tensor) {
stream << "(" << tensor.x << "," << tensor.y << "," << tensor.z << ") Tensor\n";
for (unsigned int i = 0; i < tensor.x; i++) {
for (unsigned int k = 0; k < tensor.z; k++) {
stream << "[";
for (unsigned int j = 0; j < tensor.y; j++) {
stream << std::setw(5) << roundf(tensor(i, j, k) * 1000) / 1000;
if (j + 1 < tensor.y) stream << ",";
}
stream << "]";
}
stream << std::endl;
}
return stream;
}
tensor<T> & operator +(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
tensor<T> & operator -(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
tensor<T> & operator *(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
T & operator ()(unsigned int i, unsigned int j, unsigned int k) {
return p_data[i + (j * x) + (k * x * y)];
}
T & operator ()(unsigned int i) {
return p_data[i];
}
private:
T * p_data = nullptr;
};
int main() {
tensor<double> * p_tensor_input = tensor<double>::random(6, 2, 3, 0.0, 0.0, 1.0);
tensor<double> * p_tensor_weight = tensor<double>::random(2, 6, 3, 0.0, 0.0, 1.0);
std::cout << *p_tensor_input << std::endl;
std::cout << *p_tensor_weight << std::endl;
tensor<double> p_tensor_output = *p_tensor_input + *p_tensor_weight;
return 0;
}
Your first step is #2 -- and get it correct.
After that, optimize.
Start with a container C<T>.
Define some operations on it. wrap(T) returns a C<T> containing that T. map takes a C<T> and a function on T U f(T) and returns C<U>. flatten takes a C<C<U>> and returns a C<U>.
Define scale( T, C<T> ) which takes a T and a C<T> and returns a C<T> with the elements scaled. Aka, scalar multiplication.
template<class T>
C<T> scale( T scalar, C<T> container ) {
return map( container, [&](T t){ return t*scalar; } );
}
Then we have:
template<class T>
C<T> tensor( C<T> lhs, C<T> rhs ) {
return flatten( map( lhs, [&](T t) { return scale( t, rhs ); } ) );
}
is your tensor product. And yes, that can be your actual code. I would tweak it a bit for efficiency.
(Note I used different terms, but I'm basically describing monadic operations using different words.)
After you have this, test, optimize, and iterate.
As for 3, the result of tensor products get large and complex, there is no simple visualization for a large tensor.
Oh, and keep things simple and store data in a std::vector to start.
Here are some tricks for efficient vectors i learned in class, but they should be equally good for a tensor.
Define an empty constructor and assignment operator. For example
tensor(unsigned int x, unsigned int y, unsigned int z) : x(x), y(y), z(z), s(x * y * z) {
p_data = new T[s];
}
tensor& operator=( tensor const& that ) {
for (int i=0; i<size(); ++i) {
p_data[i] = that(i) ;
}
return *this ;
}
template <typename T>
tensor& operator=( T const& that ) {
for (int i=0; i<size(); ++i) {
p_data[i] = that(i) ;
}
return *this ;
}
Now we can implement things like addition and scaling with deferred evaluation. For example:
template<typename T1, typename T2>
class tensor_sum {
//add value_type to base tensor class for this to work
typedef decltype( typename T1::value_type() + typename T2::value_type() ) value_type ;
//also add function to get size of tensor
value_type operator()( int i, int j, int k ) const {
return t1_(i,j,k) + v2_(i,j,k) ;
}
value_type operator()( int i ) const {
return t1_(i) + v2_(i) ;
}
private:
T1 const& t1_;
T2 const& t2_;
}
template <typename T1, typename T2>
tensor_sum<T1,T2> operator+(T1 const& t1, T2 const& t2 ) {
return vector_sum<T1,T2>(t1,t2) ;
}
This tensor_sum behaves exactly like any normal tensor, except that we don't have to allocate memory to store the result. So we can do something like this:
tensor<double> t0(...);
tensor<double> t1(...);
tensor<double> t2(...);
tensor<double> result(...); //define result to be empty, we will fill it later
result = t0 + t1 + 5.0*t2;
The compiler should optimize this to be just one loop, without storing intermediate results or modifying the original tensors. You can do the same thing for scaling and the kronecker product. Depending on what you want to do with the tensors, this can be a big advantage. But be careful, this isn't always the best option.
When implementing the kronecker product you should be careful of the of the ordering of your loop, try to go through the tensors in the order they are stored for cache efficiency.

C++ & Swap/Copy applied to a Point struct

I have written a Point struct I am using to model the n-body problem. I have found it difficult to fully understand and implement the copy & swap idiom and adapting it to my needs, which are mainly speed. Am I doing this correctly? Would it be different in C++17?
#pragma once
#include <algorithm>
struct Point
{
double x, y, z;
explicit Point(double X = 0, double Y = 0, double Z = 0) : x(X), y(Y), z(Z) {}
void swap(Point&, Point&);
inline bool operator==(Point b) const { return (x == b.x && y == b.y && z == b.z); }
inline bool operator!=(Point b) const { return (x != b.x || y != b.y || z != b.z); }
Point& operator=(Point&);
Point& operator+(Point&) const;
Point& operator-(Point&) const;
inline double operator*(Point& b) const { return b.x*x + b.y*y + b.z*z; } // Dot product
Point& operator%(Point&) const; // % = Cross product
inline Point& operator+=(Point& b) { return *this = *this + b; }
inline Point& operator-=(Point& b) { return *this = *this - b; }
inline Point& operator%=(Point& b) { return *this = *this % b; }
Point& operator*(double) const;
Point& operator/(double) const;
inline Point& operator*=(double k) { return *this = *this * k; }
inline Point& operator/=(double k) { return *this = *this / k; }
};
std::ostream &operator<<(std::ostream &os, const Point& a) {
os << "(" << a.x << ", " << a.y << ", " << a.z << ")";
return os;
}
void Point::swap(Point& a, Point& b) {
std::swap(a.x, b.x);
std::swap(a.y, b.y);
std::swap(a.z, b.z);
}
Point& Point::operator=(Point& b) {
swap(*this, b);
return *this;
}
Point& Point::operator+(Point& b) const {
Point *p = new Point(x + b.x, y + b.y, z + b.z);
return *p;
}
Point& Point::operator-(Point& b) const {
Point *p = new Point(x - b.x, y - b.y, z - b.z);
return *p;
}
Point& Point::operator%(Point& b) const {
Point *p = new Point(
y*b.z - z*b.y,
z*b.x - x*b.z,
x*b.y - y*b.x
);
return *p;
}
Point& Point::operator*(double k) const {
Point *p = new Point(k*x, k*y, k*z);
return *p;
}
Point& Point::operator/(double k) const {
Point *p = new Point(x/k, y/k, z/k);
return *p;
}
The copy/swap-ideom actually copies and swap()s the values. Your "adaptation" merely swap()s. A correct use of the copy/swap-ideom would look, e.g., like this:
Point& Point::operator= (Point other) { // note: by value, i.e., already copied
this->swap(other);
return *this;
}
(of course, this also assumes that your swap() function is a member taking just one additional argument: there is already an object to swap with).
If speed is your primary concern, the copy/swap-ideom is probably not particular suitable for the case of Point: the copy operation is essentially trivial. Swapping values is quite reasonable compared to relatively involved operations like copying an array old by a std::vector where the swap operation just amounts to a few pointer swaps in addition to copying probably multiple values and some allocation operations. That is, your Point assignment is probably best off to just assign all members:
Point& Point::operator= (Point const& other) { // note: no copy...
this->x = other.x;
this->y = other.y;
this->z = other.z;
return *this;
}
As was pointed out in comments, you should also not allocate new Point objects with new: C++ isn't Java or C#! You can just create an object on the stack it doesn't need to come from the heap, e.g.:
Point Point::operator+ (Point const& other) const {
return Point(this->x + other.x, this->y + other.y, this->z + other.z);
}

Getting vector from matrix by overloading subscript operator()

I want to do something like this:
Matrix m; // (4x4 matrix)
Vector4 v; // (4-elements vector)
m(0) = v; // replace first 4-elements matrix row by vector v
v = m(0); // replace vector v by first 4-elements matrix row
heres my code:
Vector4& Matrix::operator() (unsigned row)
{
return Vector4(mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}
Vector4 Matrix::operator() (unsigned row) const
{
return Vector4(mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}
the second operator works fine, but when I try to compile first one, I get this error:
error: invalid initialization of non-const reference of type ‘Vector4&’ from an rvalue of type ‘Vector4’
So where is the problem? It's good idea to overload operator() instead of operator[] in this case?
By getting only one element from matrix I use the other two operators:
float& Matrix::operator() (unsigned row, unsigned col)
{
return mat[row][col];
}
float Matrix::operator() (unsigned row, unsigned col) const
{
return mat[row][col];
}
Edit 1 (almost solution)
I think I found some solution. The first operator has been replaced to:
Matrix::MatrixHelper operator() (unsigned row)
{
MatrixHelper m;
m.f1 = &mat[row][0];
m.f2 = &mat[row][1];
m.f3 = &mat[row][2];
m.f4 = &mat[row][3];
return m;
}
heres the definition of MatrixHelper class:
class MatrixHelper
{
public:
friend class Matrix;
void operator= (const Vector4& v)
{
*f1 = v.x;
*f2 = v.y;
*f3 = v.z;
*f4 = v.w;
}
private:
float* f1;
float* f2;
float* f3;
float* f4;
};
now is possible to do something like that:
m(0) = Vector4(3,3,3,3);
but then occurs new problem, when calling this:
(m)(0) * someScalar;
the second operator is never called, so I have to implement them in my MatrixHelper class right? I'm on the right track?
Edit 2
OK this problem would be solved if the two operators would be working at the same time. But now only one of them can be enabled. I can not understand why always is working the first operator, for example having this code (just example):
Vector4& Matrix::operator() (unsigned row)
{
std::cout << "Operator one is working now\n";
}
Vector4 Matrix::operator() (unsigned row) const
{
std::cout << "Operator two is working now\n";
}
No matter if I am doing
m(0) = Vector(4,4,4,4)
or
Vector4 v = m(0)
always is working the first operator. Why?
Edit 3 (Solution)
I have found some other solution. Now all it's working, but performance may be a little problem. Solution not resolved in the way I wanted and it is a little far-fetched. Here's the code:
Operators:
Vector4 Matrix::operator() (unsigned row)
{
return Vector4 (&mat[row][0], &mat[row][1], &mat[row][2], &mat[row][3]);
}
Vector4 Matrix::operator() (unsigned row) const
{
return Vector4 (mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
}
as you can see the first operator returns a vector that takes pointers. The hard work happens now in Vector4 class instead of Matrix. Vector4 has now an extra constructor:
Vector4(float* x, float* y, float* z, float* w)
{
this->px = x; this->py = y; this->pz = z; this->pw = w;
this->x = *x; this->y = *y; this->z = *z; this->w = *w;
pointer = true;
}
first line are pointers, second - variables, and third line is a boolean type variable witch means what constructor has been called (normal or pointers).
Now comes the last operator (operator=):
Vector4 operator= ( const Vector4& v)
{
if ( pointer )
{
*px = x = v.x;
*py = y = v.y;
*pz = z = v.z;
*pw = w = v.w;
}
else
{
x = v.x;
y = v.y;
z = v.z;
w = v.w;
}
}
If pointer is true that means - px, py, pz and pw are pointers to some row elements in matrix, and we have to change them. Else - just normal vector.
So now question... it is bad bad solution, or just bad? :D
The Vector4 you are instantiating in the errored code is an r-value which is temporary. Aside from the fact that you can't assign it to a non-const reference, it will be destroyed when your function exits and the return value would be an invalid stack location.
One solution would be to return a different object by value that stores references to the individual elements you need and allows you to act upon them in a transparent way.