C++ Определить свойство RValue в классе

У меня есть вектор со значением:

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

Предположим, что математически obj разбит на три подвектора:

obj={P, Q , R}

где P={1.0,2.0,3.0}, Q={4.0,5.0,6.0} и R={7.0,8.0,9.0,10.0}

и мне нужно изменить значения подвектора Q т.е. с индекса 3 на 6;

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

Я хочу не только отрицать, но и иметь возможность выполнять любые другие действия независимо от подвектора obj.

Работает следующий код:

#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;
}

Результат

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

Однако как заставить его работать без скобок в свойстве?

я имею в виду использование

obj.Q=-obj.Q;

вместо

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

Я тоже не хочу увеличивать размер своего obj.

Кроме того, я ищу универсальное решение. Не решение, которое просто отрицает подвектор моего вектора.


Обновить

Окончательный код работает:

#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;
}

person ar2015    schedule 26.01.2016    source источник
comment
Реализуйте унарный оператор минус: stackoverflow.com/questions/2155275/   -  person Pierre    schedule 26.01.2016
comment
@Pierre, я ищу общее решение. Как насчет obj.myvec={0.7,-0.1,0.8} ?   -  person ar2015    schedule 26.01.2016
comment
Оператор присваивания @Pierre для класса myvec или B?   -  person ar2015    schedule 26.01.2016
comment
С определенным пользователем operator -> вы должны иметь возможность делать obj->myvec=-obj->myvec;   -  person Jarod42    schedule 26.01.2016
comment
@Jarod42, test.cpp:33:6: error: base operand of ‘->’ has non-pointer type ‘B’   -  person ar2015    schedule 26.01.2016
comment
@ Jarod42, obj не указатель.   -  person ar2015    schedule 26.01.2016
comment
@ar2015 ar2015: Следовательно, определяется пользователем ...   -  person ildjarn    schedule 26.01.2016
comment
@ildjarn, я не понял.   -  person ar2015    schedule 26.01.2016


Ответы (1)


С пользовательским operator -> вы можете злоупотреблять им, чтобы иметь

obj->myvec=-obj->myvec;

Например:

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}; }

};

Демо

Итак, в вашем случае код может быть примерно таким:

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)};
    }
};
person Jarod42    schedule 26.01.2016
comment
@ar2015: у меня нет arma::vec::fixed<10>, но вы можете настроить мой образец для работы с data.subvec(3,5). - person Jarod42; 26.01.2016
comment
@ar2015: добавлен код. wrapperB — это структура с нужным вам интерфейсом. B::operator -> должен вернуть оболочку с правильными данными. Обратите внимание, что если subvec возвращается по значению (например, прокси), вам нужно удалить ссылку для P, Q, R. - person Jarod42; 27.01.2016
comment
@ ar2015: отсутствует конструктор для wrapperB, который, насколько я понимаю, принимает 3 ссылки. - person Jarod42; 27.01.2016
comment
Да (а также вы используете С++ 11? иначе вы также должны быть явными в конструкции: return wrapperB(data.subvec(0,2), data.subvec(3,5), data.subvec(6,9)); - person Jarod42; 27.01.2016
comment
Большое спасибо. Поскольку при каждом вызове типа obj->Q остальные подвекторы рассчитываются через wrapperB(data.subvec(0,2), data.subvec(3,5), data.subvec(6,9)), какова производительность? компилятор генерирует для них больше ассемблерных кодов? - person ar2015; 27.01.2016
comment
Обычно (и так к сожалению) да. Но компилятор может выполнить оптимизацию, если он получит достаточно информации и не возникнет побочного эффекта. - person Jarod42; 27.01.2016