Following the question in Pointer to portions of array, a structure that does operations with portions of an array was proposed.
However, I am having a problem when calling functions that change entries in the matrices.
When defining operations for matrices it is standard to pass by reference. However, when I use the same structure for the filtered array I get:
error: cannot bind non-const lvalue reference of type ‘subMat&’ to an rvalue of type ‘subMat’
Here is the code:
#include <vector>
#include <array>
#include <iostream>
// define matrix 4x4
typedef std::array<double, 16> matrix4;
// define matrix 3x3
typedef std::array<double, 9> matrix3;
struct subMat{
matrix4& matrix_;
const double& operator[](size_t index) const
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return matrix_[mapping[index]];
}
double& operator[](size_t index)
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return matrix_[mapping[index]];
}
subMat (matrix4& A): matrix_(A){}
};
template <typename T>
double sum_of_elements(const T& arr)
{
double res = 0;
for (int i=0;i <9; i) res = arr[i];
return res;
}
template <typename T>
void test(T& arr)
{
for (int i=0;i <9; i)
{
arr[i] = 1;
}
}
int main(int argCount, char *args[])
{
std::vector<matrix4> myBlockMatrix(5);
for (int i=0; i < myBlockMatrix.size(); i )
{
for (int j = 0; j<myBlockMatrix[0].size(); j )
{
myBlockMatrix[i][j] = i*j;
}
}
for (int i = 0; i<myBlockMatrix.size(); i )
{
std::cout << sum_of_elements(subMat(myBlockMatrix[i])) << std::endl; // this owrks
}
test(subMat(myBlockMatrix[0])); // this does not work
subMat a = subMat(myBlockMatrix[0]);
test(a); // this works and changes the values in myBlockMatrix
return 0;
}
The question is: What can I do with this structure to re-use the previous functions for matrix3
. Do I need to always create a new instance of subMat
to do operations? Or is there a way to use subMat(myBlockMatrix[0])
inside the function argument?
CodePudding user response:
The clue is in the error message: Your test
function takes an lvalue reference but the temporary subMat
object constructed as the argument in the test(subMat(myBlockMatrix[0]))
call is an rvalue.
The simplest fix for this is to redeclare the test
function template to have a forwarding reference argument:
template <typename T>
void test(T&& arr) // forwarding reference
{
for (int i = 0; i < 9; i) {
arr[i] = 1;
}
}
This will allow the compiler to create versions of test
that take either lvalue or rvalue references, the latter being used in the case when the argument is a temporary object.
From the linked cppreference page:
Rvalue references can be used to extend the lifetimes of temporary objects (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them).