lwaarde vereist als linker operand van toewijzing – Array

Hieronder staat het codefragment waar de fout zit, de regel

a[i][j] = m[i][j] + w[i][j];

retourneert een fout

lwaarde vereist als linker operand van toewijzing

Ik kan geen antwoord vinden dat van toepassing is op arrays, mijn Matrix is ​​als volgt gedefinieerd:

Matrix::Matrix() {
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            coords[i][j] = 0.0f;
}
const Matrix operator+(const Matrix &m, const Matrix &w) {
    Matrix a;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 4 ; j++)
            a[i][j] = m[i][j] + w[i][j];  // <----- error
    return a;
}

Hier is de operator[]
Hoe retourneer ik via referentie

const Vector Matrix::operator[](int i) const{
    switch(i)
    {
    case 0: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    case 1: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    case 2: return Vector (coords[i][0], coords[i][1], coords[i][2]);
    }
}

Antwoord 1, autoriteit 100%

De fout is eigenlijk “lvalue vereist als linker operand van toewijzing”.

Het betekent dat je a[i][j] je een tijdelijk object geeft. Dit gebeurt wanneer u terugkeert van een functie op waarde. Een functieaanroep die op waarde retourneert, is een rvalue-expressie en u kunt een rvalue-expressie niet gebruiken als de linkeroperand van een toewijzing. U moet de implementatie van operator[] wijzigen op zowel de Matrix als de helperklasse die Matrix::operator[] retourneert, zodat ze terugsturen op referentie. Een functieaanroep die door middel van referentie retourneert, is een lvalue-expressie en stelt u in staat hieraan toe te wijzen.

template <typename T>
Vector<T>& Matrix<T>::operator[](int index) { ... }
template <typename T>
T& Vector<T>::operator[](int index) { ... }

Natuurlijk is dit logisch. Als uw operator[]s niet terugkwamen door middel van referentie, hoe zou het toewijzen aan de door hen geretourneerde waarde dan enig effect hebben op de inhoud van de Matrix?


Als reactie op je bewerking:

Je hebt een probleem met het ontwerp van je klas. De klasse Matrix lijkt een 3-op-3 array van floats op te slaan, genaamd coords. Wanneer u echter Matrix::operator[] gebruikt, kopieert het de waarden van een rij coords naar een Vector-object. Het zijn kopieën. Vervolgens retourneert u die Vector op waarde, die de Vector en de daarin opgenomen waarden uit de functie kopieert. Alles wat u met die geretourneerde Vector doet, heeft alleen invloed op die kopie.

Bovendien is je switch-statement totaal zinloos. Elke zaak is precies hetzelfde. Je hoeft alleen maar i te gebruiken als de array-indexen en deze niet aan te zetten.

Als je mensen die operator[] bellen toestaat om de inhoud van je Matrix te wijzigen, dan moet de operator[] functie mag niet const zijn.

Er zijn een paar alternatieven die uw probleem kunnen oplossen. De eerste is om in plaats daarvan een float* terug te geven en je plan te schrappen met Vector:

float* Matrix::operator[](int i) {
    return coords[i];
}

Dat is een heel eenvoudige oplossing, maar er moet wel een onbewerkte aanwijzer worden doorgegeven. De onbewerkte aanwijzer kan worden gebruikt als een array, waardoor u de syntaxis m[i][j] kunt gebruiken.

U kunt hetzelfde doen als de Eigen-bibliotheek en in plaats daarvan een operator() opgeven die twee argumenten nodig heeft, de rij-index en de kolomindex:

float& Matrix::operator()(int i, int j) {
    return coords[i][j];
}

Merk op dat de float wordt geretourneerd door verwijzing: float&. Dit betekent dat het kan worden gewijzigd van buiten de aanroep naar operator(). Hier zou u een rij en kolom indexeren met m(i, j).


Antwoord 2, autoriteit 8%

het betekent dat uw []-operator een waarde retourneert zonder een adres dat niet kan worden gebruikt voor toewijzing. Het is rechttoe rechtaan.


Antwoord 3, autoriteit 8%

Wat is Vector?

Het probleem begint waarschijnlijk met wat Matrix::operator[]
geeft terug. Om de syntaxis [][] te laten werken, moet het moet wat teruggeven
soort proxy, waarop de tweede [] kan worden toegepast, en het
zal een verwijzing naar het gewenste element in de matrix retourneren.
De gebruikelijke manier om dit te doen (althans voor mij) is om te definiëren
een “setter” en “getter” in Matrix:

void set( int i, int j, double new_value )
{
    myData[ getIndex( i, j ) ] = new_value;
}
double get( int i, int j ) const
{
    return myData[ getIndex( i, j ) ];
}

en maak dan gebruik van twee proxy’s (geneste klassen in Matrix):

class Proxy2D
{
    Matrix* myOwner;
    int myIndex1;
    int myIndex2;
public:
    Proxy2D( Matrix& owner, int index1, int index2 )
        : myOwner( &owner )
        , myIndex1( index1 )
        , myIndex2( index2 )
    {
    }
    void operator=( double new_value ) const
    {
        myOwner->set( myIndex1, myIndex2, new_value ):
    }
    operator double() const
    {
        return myOwner->get( myIndex1, myIndex2 );
    }
};
class Proxy1D
{
    Matrix* myOwner;
    int myIndex;
public:
    Proxy1D( Matrix& owner, int index )
        : myOwner( &owner )
        , myIndex( index )
    {
    }
    Proxy2D operator[]( int index2 ) const
    {
        return Proxy2D( *myOwner, myIndex, index2 );
    }
};
Proxy1D operator[]( int index1 )
{
    return Proxy1D( *this, index1 );
}

In de praktijk wil je ook dat const-varianten worden geretourneerd
door operator[]( int index1 ) const. En uiteraard,
ConstProxy2D heeft de overbelasting voor operator= niet nodig; de
impliciete conversie is voldoende.

En voor het geval het niet duidelijk is, Matrix::getIndex doet de grenzen
controleren, en berekent vervolgens de werkelijke index in de onderliggende
std::vector<double> die de gegevens bevat.


Antwoord 4

Aangezien u een nieuw geconstrueerd Vector-object retourneert om een ​​kolom (of rij, maakt niet echt uit), is deze Vector verantwoordelijk voor het bijwerken van een item in de oorspronkelijke Matrix-instantie, wat een beetje lastig maar kan gemakkelijk worden opgelost:

Je moet een andere klasse VectorRef implementeren die geen vector vertegenwoordigt op waarde maar op referentie en die dus kan worden gebruikt om toegang te krijgen tot de componenten als lvalues. Dit betekent dat het de getallen niet als waarden maar als referentie bevat en deze referenties in zijn constructor opneemt. Om het simpel te houden, kun je een aanwijzer gebruiken die naar de eerste component verwijst (gevolgd door de andere componenten):

class VectorRef {
    float *coords;
public:
    VectorRef(float *coords) : coords(coords) {}
    float & operator[](int i) { return coords[i]; }
};

Configureer vervolgens zo’n “referentieobject” in de operator[] van de matrix:

VectorRef Matrix::operator[](int i) {
    return VectorRef (coords[i]);
}

Als u de VectorRef ook als Vector wilt gebruiken, geeft u een conversie-operator op:

    // (within VectorRef:)
    operator Vector() const { return Vector(coords[0], coords[1], coords[2]); }

Hierdoor zouden de zaken vlekkeloos moeten worden.

Als u altijd de elementen binnen een matrix opent en niet de kolommen als geheel, kunt u ook de kolomaanwijzer rechtstreeks in de operator[] van de matrix retourneren:

float * Matrix::operator[](int i) {
    return coords[i];
}

Bij het schrijven van mat[x][y] zal dit eerst de floatpointer benaderen met mat[x] en vervolgens toegang krijgen tot de y-de element van die kolom, wat een lvalue is.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

nine − 5 =

Other episodes