Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Writing a wrapper class for a local object to pass to a function

40 views
Skip to first unread message

bitrex

unread,
Jun 20, 2018, 2:31:33 PM6/20/18
to
Say I have some kind of arbitrary type called Foo that I would like to
wrap in a templated wrapper class, like say EventData<Foo>. The
EventData wrapper will be constructed to hold a pointer or reference to
a local object on the stack.

I'd then like to pass a wrapper of arbitrary template type to a
non-template function call via pointer to the base type e.g.
EventDataBase* parameter (there is a possibility this could be null so
likely have to use pointers in this call instead of a reference to the
base type.) Then work with the underlying Foo-type in that function
transparently as compared to how I would work with the original type in
the caller prior to being wrapped up and passed.

What would be a good way to implement this structure? Would it be more
appropriate to store a reference to the template type in the wrapper
class vs pointer to express that its lifetime is dependent on the
lifetime of the local object it wraps?

Öö Tiib

unread,
Jun 21, 2018, 2:10:31 AM6/21/18
to
Can you post some code that "works with the underlying Foo-type
transparently"? For me virtual functions (in EventDataBase) that
you have to work with in that "non-template function" have to make
that underlying Foo rather opaque since EventDataBase has to work
well when there are no Foo (like it is EventData<Moo>).

bitrex

unread,
Jun 21, 2018, 7:41:29 PM6/21/18
to
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);
}

Öö Tiib

unread,
Jun 22, 2018, 1:55:29 AM6/22/18
to
Your example is not motivating since your do_stuff assumes that the
data is int, seemingly rendering all the code pointless. So I may
be wrong but it looks likely that you want to have something like
std::variant.

bitrex

unread,
Jun 22, 2018, 11:41:00 AM6/22/18
to
The issue I face isn't so much that the callee function itself requires
type-erasure and needs to itself be able to work with a variety of
types. It's more along the lines that the callee is used as a template
argument to a class template taking a particular type of member function
pointer to use as a callback, for example:

template <typename SomeHandlerClass, void
(SomeHandlerClass::*Func)(const EventDataBase*)>
class Bar { ... etc.

and the callee is defined as something like
aHandlerClass::do_stuff(const EventDataBase* data)

"do_stuff" is then passed as a template parameter for the construction
of Bar.

I guess I could further parameterize Bar with a third template argument
so on construction I could also make specific the argument of the member
function pointer Func takes a template parameter as well. But gosh it
seems like an unnecessary complication as the callee do_stuff "knows"
fine what type it's supposed to be working with and the conversion to
the appropriate data type can be done perfectly well at compile time
with a cast or template over there instead.

I'm kinda memory-limited so I'd prefer not to blow up the variety of
template-types that get generated.
0 new messages