Surely, I'll post a sketch of solution...there's a lot of stuff I could
do rather than feed wrappers to functions taking base class pointers
like say std::functional or std::any if I were on a desktop environment
but this is for an embedded environment where I essentially just have
the stock C++11 features and not a lot more, and the codebase I'm
working with is pre-modern C++.
I don't see any way to avoid an explicit compile-time template
parameterization or cast so the base class pointer "knows" WTF it's
supposed to be handing off to the callee to work with but that's okay in
this case.
The full assembly output from e.g. MIPS64 gcc 5.4 -std=c++11 -O1 is here:
<
https://pastebin.com/PAVvfqM4>
#include <iostream>
template <typename DataType>
class EventData;
class EventDataBase {
public:
virtual ~EventDataBase() = default;
template <typename DataType>
DataType data() const
{
auto pkg_ptr = static_cast<const EventData<DataType>*>(this);
return static_cast<DataType>(*pkg_ptr );
}
protected:
EventDataBase() = default;
private:
virtual const EventDataBase* data_() const = 0;
};
template <typename DataType, template <typename> class EventData>
class EventDataCRTP : public EventDataBase {
public:
static EventData<DataType> create_event_data(const DataType& data) {
return EventData<DataType>::create_event_data_(data);
}
};
template <typename DataType>
class EventData : public EventDataCRTP<DataType, EventData> {
friend class EventDataCRTP<DataType, EventData>;
public:
//don't want or need copying/copy assignment of wrapper class in
//callee it's holding a reference to obj on stack
EventData() = delete;
EventData(const EventData&) = delete;
EventData(EventData&&) = default;
EventData& operator=(const EventData&) = delete;
EventData& operator=(EventData&&) = default;
explicit operator const DataType&() const { return message_data_; }
protected:
static EventData<DataType> create_event_data_(const DataType& data) {
//do something here if required
return EventData<DataType>{data};
}
private:
EventData(const DataType& data) : message_data_{data} {}
const EventDataBase* data_() const override { return this; }
private:
const DataType& message_data_;
};
void do_stuff(const EventDataBase* data)
{
//use it here
std::cout << data->data<int>() << std::endl;
}
int main()
{
int foo = 1;
//make a wrapper here
auto bar = EventData<int>::create_event_data(foo);
do_stuff(&bar);
}