1

I have a vector with value:

obj={1.0,2.0,3.0, 4.0,5.0,6.0 ,7.0,8.0,9.0,10.0}

Assuming that, mathematically obj is partitioned into three subvectors:

obj={P, Q , R}

where P={1.0,2.0,3.0}, Q={4.0,5.0,6.0}, and R={7.0,8.0,9.0,10.0}

and I need to change the values of the sub-vector Q i.e. from index 3 to 6;

obj={1.0,2.0,3.0, -4.0,-5.0,-6.0 ,7.0,8.0,9.0,10.0}

Not only negate, but also I want to be able to do any other action independently on a subvector of obj.

The following code works:

#include <armadillo>
#include <iostream>

using namespace std;

typedef arma::vec::fixed<10> x_vec;

class B
{
public:
    x_vec data;

    B(x_vec init) :
        data(init)
    {
    }

    inline decltype(data.subvec(0,2)) P()
    {
        return data.subvec(0,2);
    }

    inline decltype(data.subvec(3,5)) Q()
    {
        return data.subvec(3,5);
    }

    inline decltype(data.subvec(6,9)) R()
    {
        return data.subvec(6,9);
    }

};

int main()
{
    B obj({1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0});
    cout<<"sizeof obj.data: "<<sizeof(obj.data)<<endl;
    cout<<"sizeof obj: "<<sizeof(obj)<<endl;
    cout<<"value of obj:"<<endl;
    obj.data.print();

    obj.Q()=-obj.Q();

    cout<<"value of obj:"<<endl;
    obj.data.print();

    return 0;
}

Result

sizeof obj.data: 192
sizeof obj: 192
value of obj:
    1.0000
    2.0000
    3.0000
    4.0000
    5.0000
    6.0000
    7.0000
    8.0000
    9.0000
   10.0000
value of obj:
    1.0000
    2.0000
    3.0000
   -4.0000
   -5.0000
   -6.0000
    7.0000
    8.0000
    9.0000
   10.0000

However, how to make it work without parenthesis on the property?

I mean using

obj.Q=-obj.Q;

instead of

obj.Q()=-obj.Q();

I don't want to increase the size of my obj too.

Also, I am looking for a general purpose solution. Not a solution that just negates a subvector of my vector.


Update

The final code works:

#include <armadillo>
#include <iostream>

using namespace std;

typedef arma::vec::fixed<10> x_vec;

struct wrapperB
{
    wrapperB* operator ->() { return this; }

    typedef decltype(std::declval<x_vec>().subvec(0, 2)) P_type;
    typedef decltype(std::declval<x_vec>().subvec(3, 5)) Q_type;
    typedef decltype(std::declval<x_vec>().subvec(6, 9)) R_type;

    P_type& P;
    Q_type& Q;
    R_type& R;

    wrapperB(P_type _p,Q_type _q,R_type _r) :
        P(_p), Q(_q), R(_r)
    {
    }
};

class B
{
public:
    x_vec data;

    B(x_vec init) : data(init) {}

    wrapperB operator -> ()
    {
        return wrapperB(data.subvec(0,2), data.subvec(3,5), data.subvec(6,9));
    }
};

int main()
{
    B obj({1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0});
    cout<<"sizeof obj.data: "<<sizeof(obj.data)<<endl;
    cout<<"sizeof obj: "<<sizeof(obj)<<endl;
    cout<<"value of obj:"<<endl;
    obj.data.print();

    obj->Q=-obj->Q;

    cout<<"value of obj:"<<endl;
    obj.data.print();

    return 0;
}
ar2015
  • 5,558
  • 8
  • 53
  • 110

1 Answers1

1

With user defined operator ->, you may abuse of it to have

obj->myvec=-obj->myvec;

For example:

template <typename T>
struct wrapper
{
    wrapper<T>* operator ->() { return this; }

    std::vector<T>& myvec;
};

template <typename T>
class B
{
public:
    std::vector<T> data;

    B(const std::vector<T>& init) : data(init) {}

    wrapper<T> operator -> () { return {data}; }

};

Demo

So in your case, code might be something like:

struct wrapperB
{
    wrapperB* operator ->() { return this; }

    decltype(std::declval<x_vec>().subvec(0, 2))& P;
    decltype(std::declval<x_vec>().subvec(3, 5))& Q;
    decltype(std::declval<x_vec>().subvec(6, 9))& R;
};

class B
{
public:
    x_vec data;

    B(x_vec init) : data(init) {}

    wrapperB operator -> ()
    {
        return {data.subvec(0,2), data.subvec(3,5), data.subvec(6,9)};
    }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • @ar2015: I don't have `arma::vec::fixed<10>`, but you can arrange my sample to work with `data.subvec(3,5)`. – Jarod42 Jan 26 '16 at 14:25
  • @ar2015: code added. `wrapperB` is the struct with the interface you want. `B::operator ->` should return the wrapper with correct data. Care that if `subvec` return by value (a proxy for example), you have to remove the reference for `P`, `Q`, `R`. – Jarod42 Jan 27 '16 at 12:17
  • @ar2015: missing constructor for `wrapperB` which takes the 3 references as I understand. – Jarod42 Jan 27 '16 at 12:56
  • Yes, (And also are you using C++11 ? else you have to be explicit in construction too:`return wrapperB(data.subvec(0,2), data.subvec(3,5), data.subvec(6,9));` – Jarod42 Jan 27 '16 at 13:14
  • Thnaks a lot. Since at each call like `obj->Q`, the other subvectors are calculated via `wrapperB(data.subvec(0,2), data.subvec(3,5), data.subvec(6,9))` how is the performance? does compiler generate more assembly codes for them? – ar2015 Jan 27 '16 at 13:33
  • Normally (and so unfortunately), yes. But compiler might do optimization if it got enough information, and no side effect occurs. – Jarod42 Jan 27 '16 at 13:56