ndrey
ndrey

Reputation: 45

Making return-type dependent on source of invocation?

I wrote a c++-class that represents a mathematical matrix of arbitrary dimension NxM. Furthermore I also wrote a vector-class, deriving from it...

template<size_t N, size_t M>
class matrix{ ... };

template<size_t N>
class vector : public matrix<N,1>{ ... };

...so that an N-vector can be treated as an Nx1-matrix, for example when it comes to multiplying with integral values or addition/subtraction of equally dimensioned matrices (or vectors in this regard). The idea behind this is to avoid repeating code - which generally is a noble goal, I think. But here is the problem arising from it:

Here is your operator-overload for the addition, which only exists in the matrix-class:

matrix<N,M> operator+(const matrix<N,M>& right){
  //calculate some result and use it to construct a new instance
  return matrix<N,M>(result);
}

Making sure, the vector-class offers a copy-constructor for it's matrix-representation, it should be possible to say something like this:

vector<3> a(1,2,3);
vector<3> b(3,2,1);
a = a+b; 

but you can't say this:

(a+b).some_vector_instance_method();

...because (a+b) isn't a vector.

QUESTION: Is it possible to implement the matrix-operator+, so that it makes the return-type dependent on it's source of invocation? So, basically, if you invoke the + on a matrix, it should return a matrix; if invoked on a vector, it should return a vector.

Now you can do this:

template<typename D>
D operator+(const D& right){
  //calculate result as usual, relying on 'right' to have what it takes
  return D(result);
}

... but it is unsafe as hell.

Any ideas?

Upvotes: 0

Views: 95

Answers (1)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153820

The simple approach to implementation is to implement a member operator+=() for both matrix<M, N> and for vector<M> where the latter simply delegates to the former an the matrix operator has the actual operation. Using a bit of tagging the operator+() is then implemented as a non-member operator in terms of these operator. Here is a brief sketch:

#include <iostream>

namespace matrix_operators
{
    struct tag {};
    template <typename T>
    T operator+ (T const& lhs, T const& rhs) {
        return T(lhs) += rhs;
    }
}

template<size_t N, size_t M>
class matrix
    : matrix_operators::tag
{
public:
    matrix<N, M>& operator+= (matrix<N, M> const&) {
        std::cout << "matrix<" << N << ", " << M << "::operator+=()\n";
        return *this;
    }
};

template<size_t N>
class vector:
    public matrix<N,1>
{
public:
    vector<N>& operator+= (vector<N> const& other) {
        matrix<N, 1>::operator+= (other);
        return *this;
    }
    void some_other_method() {
        std::cout << "vector<" << N << ">::some_other_method()\n";
    }
};

int main()
{
    vector<3> a, b;
    (a + b).some_other_method();
}

Upvotes: 2

Related Questions