tags:

views:

482

answers:

5

I want to create a collection of classes that behave like math vectors, so that multiplying an object by a scalar multiplies each field by that ammount, etc. The thing is that I want the fields to have actual names, instead of being treated as an index.

My original idea to implement this was creating a base class Rn with the overloads and then create derived classes with the pretty names. Something like this:

#include <iostream>
#include <algorithm>
using namespace std;

template<int N, class X=double>
struct Base{
    X xs[N];

    Base(){};

    Base(X *data){
        copy(data, data+N, xs);
    }

    Base operator*= (double d){
        for(int i=0; i<N; i++){
            xs[i] *= d;
        }
        return *this;
    }

    Base operator* (double d){
        Base answer = *this;
        answer *= d;
        return answer;
    }

    //also operators for +=, +, multiplication from left, maybe [] too
};

struct Derived : public Base<2>{
    Derived(double a, double b){
        foo() = a;
        bar() = b;
    }

    double &foo(){ return xs[0]; }
    double &bar(){ return xs[1]; }
};

int main()
{
    //this is OK:
    double data[2] = {0.0, 2.0};
    Base<2> b(data);
    b = b*17.0;

    cout << b.xs[0] << endl;

    //I can't do this:
    Derived x(0.0, 2.0);
    x = x*17.0;

    cout << x.foo() << endl;

    return 0;
}

I get a compiler error whenever I try to use of of the operators that requires copying. gcc gave me the following compiler error:

teste.cpp: In function ‘int main()’:
teste.cpp:52: error: no match for ‘operator=’ in ‘x = x.Derived::<anonymous>.Base<N, X>::operator* [with int N = 2, X = double](1.7e+1)’
teste.cpp:31: note: candidates are: Derived& Derived::operator=(const Derived&)

I think the problem is that the overloading functions deal with Base objects that can't be converted to Derived ones, so I can't use them in the derived class. However, I can't come up with a solution. Is there a way around this or should I use a totally different approach?

Bonus question: is there some way that I can use std::valarray to keep from having to type lots and lots of operator overloads?

+1  A: 

I think you're going to be much better off using an enum or static constants to name your fields

e.g., static const int FIELD_NAME = 0;
Static const int FIELD_NAME2 = 1;

than doing this as different types (templates). Then you can go for std::valarray or boost::ublas::vector/matrix types to leverage existing code & get quality performance vector operations to boot.

ceretullis
+3  A: 

Your Base operators (* in this case) can accept Derived object, but they return a Base, which can't be used as a right-hand operand in Derived default assignment operator. Easiest way to fix this is just add an assignment operator to Derive that will take a Base:

Derived& operator= (const Base<2>& other)

You will have to add it to any derived class, but the implementation is rather straightforward (you can have a void CopyOtherBase function in Base that will do the copy, and have all operator= call it and return *this).

eran
David Rodríguez - dribeas
You are right, of course. Thanks for the correction, I fixed my answer.
eran
+2  A: 

I'll only address the technical difficulty, not whether this is a good idea or not.

The problem is that the result of operator* of Derived is a Base, and operator= of Derived (which is a default operator=) doesn't know how to "eat" a Base.

A simple solution is to create a constructor of Derived that gets a Base, and does whatever is needed to initialize itself correctly. This would allow an on-the-fly conversion of a Base to a Derived - and would work for all other operators of Derived that expect a Base.

Something along the lines of -

Derived(const Base<2>& B) : Base<2>( B )
{
}
Hexagon
David Rodríguez - dribeas
(probably should read Base<2> whereever I wrote Base above.
David Rodríguez - dribeas
Absolutely correct. Edited to reflect this insight. Thanks!
Hexagon
A: 

Template metaprogramming had an interesting idea on solving just this sort of issue with math vectors, but perhaps doesn't solve your issue of naming the parts.

David Abrahams, Aleksey Gurtovoy: C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, Addison-Wesley, ISBN 0-321-22725-5

Greg Domjan
A: 

According to MSDN,

All overloaded operators except assignment (operator=) are inherited by derived classes.

Could this be your problem?

gbjbaanb