Вопрос

Is it somehow possible for a class to act as a proxy when accessing it's members? The simplest way would be of course to write getters/setters but this is inflexible und unelegant since you have to write all of the setters yourself which bloats the code up.

The problem is that I want to abstract away the fact that some data lies in the progmem of the microcontroller. Basically I want that

MemberType member = object->member; // won't work if object lies in progmem

to be translated to something like

MemberType member; // Allocate memory in RAM for the member
memcpy_P(&member, 
         &object->member, // assuming that this gives a valid pointer to the member
         sizeof(MemberType));

In embedded C one can use the address space __flash to do something like that. Unfortunately C++ does not support this.

So I thought about overloading operator->(). Unfortunately operator->() does not get any information which member you are gonna access (btw: why wtf? The sole purpose of -> is to access a member so why should anybody want to throw this information away?). . can't be overridden at all.

Has anybody an idea how to solve that problem? The syntax does not have to be -> of course. If it is possible with some esoteric template construct I would be happy as well. I don't know enough C++ maybe is is not possible at all. C++ seems to be a bit inflexible on the meta-programming side.

Edit: After the inspiration from the answer I now decided to use a wrapper class and override the cast operator.

template<typename Type>
class InProgmem {
  Type const self; // InProgmem<Type> should be as big as Type
  InProgmem(Type val) : self(val) {} // Keep the compiler quiet
public:
  operator Type() const {
    Type out; 
    memcpy_P(&out, this, sizeof(Type));
    return out;
  }
} __attribute__((packed));

// Example use:
PROGMEM prog_uchar foo = 14;
class Test {
public:
  InProgmem<unsigned char> bar;
};
Test *baz = (Test*)&foo;
unsigned char bar = baz->bar;
Это было полезно?

Решение

You could create a new class ProgmemMemberType and define some assignment operators to convert between memory spaces.

const MemberType &MemberType::operator=(const ProgmemMemberType &other)
{
    memcpy_P(this, 
             other.progMemPointer(),
             sizeof(MemberType));
    return *this;
}

const ProgmemMemberType &ProgmemMemberType::operator=(const MemberType &other)
{
    // Whatever the reverse of memcpy_P is...
    return *this;
}

Then you can write MemberType member = object->member or object->member = member and the assignment operator will do the work.

This is the cleanest solution I can think of; the -> operator is not really meant for this kind of thing.

And of course if you don't want to define a new wrapper class for every type you use, you can use a template class.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top