我怎样才能让编译时 const 对象配置有可变长度的数据块?
How can I have a compile-time const object configured with a chunk of data of variable length?
目前我正在为这样的事情苦苦挣扎:
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
当然,std::vector
在这里不起作用,但它在这里是因为它最能表达我的意图。我尝试了 std::array
和其他一些想法,但都失败了。
背景:这是针对嵌入式开发的,所以我的资源很紧张,const 的东西往往会把它们放到内存便宜的地方。将它作为一个真正的向量来做会将其放入稀缺的 RAM 内存中。这是在 gcc 版本 5.2.0 上。
TL;DR:我需要一个可变长度的容器,我可以将其作为一个字段放在 const 对象上,并在 constexpr 上下文中对其进行初始化。知道那会是什么样子吗?不必花哨,如果它是一个 uint8_t*
和一个 size_t
的大小,那也可以。
deeply embedded一般使用循环缓冲区来解决这类问题。
它们有一个固定的最大大小,但根据实现的不同,它们的行为就像列表一样。
不幸的是,标准 c++ 库没有任何循环缓冲区,但网上有很多教程。
我怀疑你可以在你的受限系统上使用 boost 库,但如果你这样做,你可以简单地使用 boost::circular_buffer
其他一些可以帮助您实现适合您的循环缓冲区的页面可能是 this or this
从你的描述和代码片段来看,这似乎符合标准。
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};
您也可以编写辅助函数来避免显式输入参数计数
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);
或者,在 C++17 中有模板推导指南
template<typename... Args>
Command(Args...) -> Command<sizeof...(Args)>;
constexpr Command cmd4{0, 1, 2, 3};
constexpr Command cmd2{0, 1};
但是请注意,不同尺寸的 Command
是不同的类型,这意味着它们无法放入容器中。
目前我正在为这样的事情苦苦挣扎:
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
当然,std::vector
在这里不起作用,但它在这里是因为它最能表达我的意图。我尝试了 std::array
和其他一些想法,但都失败了。
背景:这是针对嵌入式开发的,所以我的资源很紧张,const 的东西往往会把它们放到内存便宜的地方。将它作为一个真正的向量来做会将其放入稀缺的 RAM 内存中。这是在 gcc 版本 5.2.0 上。
TL;DR:我需要一个可变长度的容器,我可以将其作为一个字段放在 const 对象上,并在 constexpr 上下文中对其进行初始化。知道那会是什么样子吗?不必花哨,如果它是一个 uint8_t*
和一个 size_t
的大小,那也可以。
deeply embedded一般使用循环缓冲区来解决这类问题。 它们有一个固定的最大大小,但根据实现的不同,它们的行为就像列表一样。 不幸的是,标准 c++ 库没有任何循环缓冲区,但网上有很多教程。
我怀疑你可以在你的受限系统上使用 boost 库,但如果你这样做,你可以简单地使用 boost::circular_buffer
其他一些可以帮助您实现适合您的循环缓冲区的页面可能是 this or this
从你的描述和代码片段来看,这似乎符合标准。
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};
您也可以编写辅助函数来避免显式输入参数计数
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);
或者,在 C++17 中有模板推导指南
template<typename... Args>
Command(Args...) -> Command<sizeof...(Args)>;
constexpr Command cmd4{0, 1, 2, 3};
constexpr Command cmd2{0, 1};
但是请注意,不同尺寸的 Command
是不同的类型,这意味着它们无法放入容器中。