1

I am creating wrappers for C structs containing register definitions with heavy use of bitfields. I would like to create reference getters for all of them, to provide consistent shorthand API (real structures may use deep nesting with long names only a HW engineer would love).

For regular values, returning a reference is easy, but for bitfields, I had to create a wrapper similar to std::bitset::reference:

#include <cstdint>
#include <cstdio>

class storage {
    public:
    auto get_x() { return x_ref{ *this }; }
    auto get_y() { return y_ref{ *this }; }
    auto& get_z() { return z; }

    private:
    uint8_t x : 3;
    uint8_t y : 5;
    uint8_t z;

    struct x_ref {
        storage& store;
        operator uint8_t() { return store.x; }
        auto& operator=(uint8_t value) { store.x = value; return *this; }
    };
    
    struct y_ref {
        storage& store;
        operator uint8_t() { return store.y; }
        auto& operator=(uint8_t value) { store.y = value; return *this; }
    };
};

int main(int argc, char **argv) {
    storage s{};
    s.get_x() = 3;
    s.get_y() = 5;
    s.get_z() = 7;
    
    uint8_t x = s.get_x(), y = s.get_y(), z = s.get_z();
    std::printf("%u, %u\n", x, y, z);
}

Is there any way to create x/y_ref as a generic template? I would like to be able to write something like auto get_x() { return ref<&storage::x>{ *this }; } which is not a valid syntax for bitfields. std::bitset::reference does not have this problem, since it always stores a reference to uint8_t& (or larger word) and index, so it doesn't have anything to template on.

7
  • 1
    As you cannot use (member) references, remain lambda (but I fear you have to type almost the whole getter/setter) or MACRO. Commented Jun 24 at 8:35
  • OT: Instead of reimplementing the bitfield, use the existi8ng C structure itself. Bitfields are one of the worst defined features in both C and C++, and most things about them are implementation specific. Commented Jun 24 at 8:38
  • @Jarod42 By lambda you mean something like return ref{ [this]() { return this->x; }, [this](auto value) { this->x = value; } };? Commented Jun 24 at 8:48
  • @Someprogrammerdude I want to provide a shorthand for a subset of bitfields that application actually uses, which are hidden all over the place. s.get_foo() vs s.feature_x_static_values.u.version_2137.blah.blah.blah.finally_getting_somewhere.oh_here_it_is.my_foo, just with much more useless Hungarian. Commented Jun 24 at 8:51
  • 1
    @DominikKaszewski: yes, it is what I meant with lambda. Commented Jun 24 at 9:25

1 Answer 1

3

Here is one way to do it, but as Jarod42 said the lambdas are about as long as writing a struct helper.

I intentionally made the assignment return a void rather than the conventional return *this;. Chaining assignment is probably not the right thing to do here.

#include <cstdint>
#include <cstdio>

template <typename GET, typename SET>
struct var_ref {
    GET getter;
    SET setter;

    using store_t = decltype(getter());
    var_ref(GET g, SET s) : getter{g}, setter{s} {}

    // Using implicit conversion as the getter.
    operator store_t() { return getter(); }

    // Using void= as the setter.
    void operator=(store_t value) { setter(value); }
};

class storage {
    uint8_t x : 3;
    uint8_t y : 5;
    uint8_t z;

public:
    auto get_x() { return var_ref{[this]{ return x; }, [this](uint8_t value) { x = value; }}; }
    auto get_y() { return var_ref{[this]{ return y; }, [this](uint8_t value) { y = value; }}; }
    auto& get_z() { return z; }
};

int main() {
    storage s{};
    s.get_x() = 3;
    s.get_y() = 5;
    s.get_z() = 7;

    uint8_t x = s.get_x(), y = s.get_y(), z = s.get_z();
    std::printf("%u, %u, %u\n", x, y, z);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.