//  (C) Porkolab 2003
//
//  A.3.4.
//
//  Return types




One of the typical usage of the references is returning from
function by reference rather than by value. Returning reference
often more effective than copying. In some cases, however,
copying is a must.


See this implementation of a template matrix:


template <typename T>
class matrix
{
public:
    // ...
          T& operator()(int i, int j)       { return v[i*cols+j]; }
    const T& operator()(int i, int j) const { return v[i*cols+j]; }

    matrix& operator+=( const matrix& other)
    {
        for (int i = 0; i < cols*rows; ++i)
            v[i] += other.v[i];
    }
private:
    // ...
    T* v;
};

template <typename T>
matrix<T> operator+( const matrix<T>& left, const matrix<T>& right)
{
    matrix<T> result(left);
    result += right;

    return result;
}


Let us discover the return values one by one:



    T& operator()(int i, int j)  { return v[i*cols+j]; }


This function returns reference to the selected value,
allowing clients to modify the appropriate element of
the matrix:


    matrix<double> dm(10,20);
    // ...
    dm(2,3) = 3.14;  // modify metrix element
    cout << dm(2,3); // copies matrix element
    dm(2,3) += 1.1;  // modify matrix element

    double& dr = dm(2,3);   // doesn't copies
    dr += 1.1;              // modify matrix element



A second version of operator() is presented to read constant
matrices.


    const T& operator()(int i, int j) const { return v[i*cols+j]; }


This const memberfunction must return const reference,
otherwise the const-correctness would be leaking:


    const matrix<double> cm = dm;
    // ...
    cm(2,3) = 3.14;  // syntax error: returns with const reference
    cout << cm(2,3); // ok: copies (read) matrix element
    cm(2,3) += 1.1;  // syntax error: returns with const reference

    double& dr = cm(2,3);   // syntax error: const reference 
                            // not converts to reference
    const double& cdr = cm(2,3);    // ok, doesn't copies   



Most assignment operators defined with (non-const) reference
type as return value:


    matrix& operator=(const matrix& other);

    matrix& operator+=( const matrix& other)
    {
        for (int i = 0; i < cols*rows; ++i)
            v[i] += other.v[i];
    }


This is more effective than a value returning type, and also avoiding
unneccessary restrictions:


    dm1 = dm2 = dm3;

    ++( dm1 += dm2 );



In the previous examples returning reference (or constant reference)
was safe, because the memory area which was referred survived the
operation. In the next addiotion returning a reference (or constant
reference) would be a major fault:


template <typename T>
matrix<T> operator+( const matrix<T>& left, const matrix<T>& right)
{
    matrix<T> result(left);     // local variable: automatic storage
    result += rigth;

    return result;      // result will disappear: must copy
}