Home > Enterprise >  Pointer to portions of array. Operations with filtered array
Pointer to portions of array. Operations with filtered array

Time:10-26

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

  • Related