It depends on whether the callback mechanism is your own or provided by
the API you're using (I'm not familiar with the Arduino environment).
If it's not your own then presumably the `void*` parameter of the
callback is intended to pass an object pointer. In that case you provide
that object pointer when you install the callback. And so you'll need to
pass that down to the code that installs the callback.
--------------------------------------------------------------------------
template< class T > using Type_ = T;
namespace c_style_api {
extern "C" using Callback = void( void* p_state, const char*
something );
extern "C"
void enumerate_something( const Type_<void*> p_state, const
Type_<Callback*> f )
{
f( p_state, "Look, it's " );
f( p_state, "calling back!" );
}
}
#include <string>
using std::string;
struct Something
{
int m_i;
string m_s;
void callback( Type_<const char*> s )
{
m_s += s;
}
};
extern "C"
void something_cb( const Type_<void*> p_state, const Type_<const char*> s )
{
reinterpret_cast<Something*>( p_state )->callback( s );
}
#include <iostream>
using std::cout, std::endl;
auto main()
-> int
{
Something smth = {};
c_style_api::enumerate_something( &smth, something_cb );
cout << smth.m_s << endl;
}
--------------------------------------------------------------------------
If it's your own callback, however, then you can simply switch from C
function pointer to C++ `function<void()>` (from the <functional>
header), and use a lambda that captures a reference to your object:
--------------------------------------------------------------------------
#include <functional>
using std::function;
template< class T > using Type_ = T;
namespace api {
using Callback = void( const char* something );
void enumerate_something( const function<Callback> f )
{
f( "Look, it's " );
f( "calling back!" );
}
}
#include <string>
using std::string;
struct Something
{
int m_i;
string m_s;
void callback( Type_<const char*> s )
{
m_s += s;
}
};
#include <iostream>
using std::cout, std::endl;
auto main()
-> int
{
Something smth = {};
api::enumerate_something( [&](auto s){ smth.callback( s ); } );
cout << smth.m_s << endl;
}
--------------------------------------------------------------------------
Or alternatively, in C++03 style you can use an interface with a known
virtual function. In that case your object's class needs to implement
the relevant interface.
--------------------------------------------------------------------------
template< class T > using Type_ = T;
namespace api {
// The pure interface class, C++03 style callback:
struct Event_handler{ virtual void on_some_event( const char*
something ) = 0; };
void enumerate_something( Event_handler& o )
{
o.on_some_event( "Look, it's " );
o.on_some_event( "calling back!" );
}
}
#include <string>
using std::string;
struct Something:
api::Event_handler
{
int m_i;
string m_s;
void on_some_event( Type_<const char*> s ) override
{
m_s += s;
}
};
#include <iostream>
using std::cout, std::endl;
auto main()
-> int
{
Something smth = {};
api::enumerate_something( smth );
cout << smth.m_s << endl;
}
--------------------------------------------------------------------------
- Alf