C++ API design: is using void* a bad idea?

  • A+
Category:Languages

I am working on an API that I want as generic as possible on the caller side. Main design idea is to provide a signal/slot sort of implementation that allows the user of the API to subscribe to a given set of events, and attach user-defined callbacks to them.

Public interface looks something like this:
RetCallback subscribe(EventEnum& ev, std::function<void(void*)> fn) const; : note the void(void*) signature here. EventEnum is given in a public header file, as well as types definition.

Inner-works of the API would then notify its subscribed observers of the event through a notify method and provide data to forward to the client :

void dummyHeavyOperation() const {     std::this_thread::sleep_for(2s);     std::string data = "I am working very hard";     notify(EventEnum::FooEvent, &data); } 

Client subscribes and casts data to (documented) type as follows:

auto subscriber = Controller->subscribe(EventEnum::FooEvent, callback); 

where

void callback(void* data) {     auto* myData = (std::string*) data;     std::cout << "callback() with data=" << *myData << std::endl;      /// Do things } 

Is this a reasonable design or is this frowned upon? What is your experienced modern C++ developer mind tells you?

[EDIT]
I should add as well that the API is delivered as a shared library loaded at run-time. So any compile time coupling (and code generation for that matter, unless I'm mistaken) is off the table

Thanks!


C++ API design: is using void* a bad idea?

Yes.

To implement equivalent API, you should use std::any, which is a checked version of type erasure. std::any is only available in the standard library since the current, C++17 standard version. If you don't have C++17 (or don't want user of the API to depend on C++17), then you can use a non-standard implementation instead.

An alternative is to not erase the argument type at all, but use templates all the way instead. See Boost Signals for an example of such callback API

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: