Krzysztof Bociurko
Krzysztof Bociurko

Reputation: 4661

How can I have a compile-time const object configured with a chunk of data of variable length?

Currently I'm struggling with something like this:

class Command final {
    const std::vector<uint8_t> cmd;
public:
    constexpr Command(const std::initializer_list<uint8_t> cmd_)
        :cmd(cmd_)
        {}
    void copyToWithSlightModifications(uint8_t* buf, size_t len) { /*...*/ }
    std::string getSomeInformation() { /*...*/ }
}

const Command cmd1({ 0x01, 0x02, 0x03 });
const Command cmd2({ 0x01, 0x02, 0x03, 0x04 });
// lots more of these

Of course, std::vector is not something that works here, but it's here as it expresses my intent best. I tried std::array and a few other ideas, but also have failed.

Background: this is for embedded development, so I'm tight on resources and consting things tends to put them to flash where memory is cheap. Doing it as a real vector will put this into scarce RAM memory. This is on gcc version 5.2.0.

TL;DR: I need to have a variable length container that I can put as a field on a const object with and initialize it in constexpr context. Any idea what that might look like? Doesn't have to be anything fancy, if it's a uint8_t* and a size_t with it's size, that will work too.

Upvotes: 1

Views: 166

Answers (2)

Passer By
Passer By

Reputation: 21160

Going off of your description and the code snippet, this seems to fit the criteria.

template<size_t N>
class Command
{
    uint8_t cmd[N];
public:
    template<typename... Args>
    constexpr Command(Args... args) : cmd{uint8_t(args)...}
    {
        static_assert(sizeof...(Args) == N,
                      "argument count mismatch");
    }
};

constexpr Command<4> cmd4{0, 1, 2, 3};
constexpr Command<2> cmd2{0, 1};

You may also write a helper function to avoid explicitly typing the argument count

template<typename... Args>
constexpr Command<sizeof...(Args)> make_command(Args... args)
{
    return {args...};
}

constexpr auto cmd4 = make_command(0, 1, 2, 3);
constexpr auto cmd2 = make_command(0, 1);

Alternatively, in C++17 there is template deduction guides

template<typename... Args>
Command(Args...) -> Command<sizeof...(Args)>;

constexpr Command cmd4{0, 1, 2, 3};
constexpr Command cmd2{0, 1};

Note however, a different sized Command is a different type, meaning they won't fit in a container.

Upvotes: 3

Detonar
Detonar

Reputation: 1429

In deeply embedded you usually use circular buffers so solve this kind of problem. They have a fixed maximal size but depending on implementation they behave just like lists. Unfortunately the standard c++ library does not have any circular buffers but there are plenty of tutorials on the web.

I doublt you can use boost library on your restricted system but in case you do you can simply use boost::circular_buffer

Some other pages that might help you implement an circular buffer suitable for you might be this or this

Upvotes: 0

Related Questions