I'm trying to use the CONTAINER_OF macro in a C++ application for Zephyr RTOS. My struct looks like this:
struct auto_update_config {
std::function<int()> update_value_func;
k_work_delayable update_work;
uint32_t num_failures;
k_timeout_t update_period;
};
When I try to use CONTAINER_OF:
static void auto_update_work_handler(struct k_work* work) {
struct k_work_delayable* dwork = k_work_delayable_from_work(work);
struct auto_update_config* ctx =
CONTAINER_OF(dwork, struct auto_update_config, update_work);
int err = ctx->update_value_func();
...
}
The compiler gives a warning:
warning: 'offsetof' within non-standard-layout type 'auto_update_config' is conditionally-supported [-Winvalid-offsetof]
451 | CONTAINER_OF(dwork, struct auto_update_config, update_work);
I imagine the std::function is what's causing this warning, but I'm not sure what to do about it. I need the struct to contain a field for a function with this signature, and I can't use a C-style definition int (*update_value_func)() because the value is the result of a std::bind.
Is there a way to achieve this same effect without getting this warning (other than just disabling the warning flag)?
You could separate your
auto_update_configstructure into two parts. One that contains theupdate_workmember that you applyCONTAINER_OFto, and the other one with the rest of the members, that derives from the first one. Then you can use astatic_castto convert from the base class to the derived class to have access toupdate_value_funcand other members.The trick here is that
auto_update_config_baseremains a standard-layout class and hence supportsoffsetof. Thestatic_castsupports non-standard-layout classes and will work correctly as long as the pointed object is always of theauto_update_configclass.