Consider the snippet:
# include <iostream>
# include <boost/scoped_ptr.hpp>
# include <boost/shared_ptr.hpp>
# include <boost/function.hpp>
# include <boost/array.hpp>
# include <boost/asio.hpp>
# include <boost/thread.hpp>
# include <boost/thread/locks.hpp>
# include <boost/bind.hpp>
# include <boost/noncopyable.hpp>
# include <boost/variant.hpp>
class DataLink {};
class Metadata {};
class Image {};
typedef boost::function<void( DataLink const&, Metadata const& , Image const& )> Handler ;
typedef boost::function<void( Metadata const& , Image const& )> Handler2 ;
typedef boost::function<void( Image const& )> Handler3 ;
typedef boost::variant<DataLink, Metadata, Image> Variant;
enum callbackHandler { link_enum, meta_enum, image_enum };
class Worker {
Handler callBack ;
//Handler2 callBack2 ;
//Handler3 callBack3 ;
DataLink dlink;
Metadata meta ;
Image img ;
callbackHandler handlerEnum ;
public :
Worker ( const Handler& handler )
: callBack ( handler )
{}
//Worker ( const Handler2& handler )
//: callBack2 ( handler )
// {}
//Worker ( const Handler3& handler )
//: callBack3 ( handler )
// {}
void Image ( ) {
// update the img object
// invoke call back
handlerEnum = image_enum ;
//const std::type_info& xxx = callBack.target_type();
//std::cout << xxx.raw_name() << std::endl;
callBack ( dlink, meta, img ) ;
}
void Metadata ( ) {
// update the meta object
// invoke call back
handlerEnum = meta_enum ;
callBack ( dlink, meta, img ) ;
}
void Dlink ( ) {
// update the link object
// invoke call back
handlerEnum = link_enum ;
callBack ( dlink, meta, img ) ;
}
callbackHandler getHandlerType() { return handlerEnum ; }
};
class Foo {
Worker *ptrWorker ;
public :
Foo ()
: ptrWorker( 0 )
{}
void callback ( DataLink const& d, Metadata const& m , Image const& i ) {
callbackHandler tt = ptrWorker->getHandlerType();
if ( tt == image_enum ) {
std::cout << "Image object " << std::endl;
}
if ( tt == meta_enum ) {
std::cout << "Meta object " << std::endl;
}
if ( tt == link_enum ) {
std::cout << "Link object " << std::endl;
}
}
bool start () {
ptrWorker = new ( std::nothrow ) Worker ( boost::bind ( &Foo::callback, this, _1, _2, _3 ) );
if ( !ptrWorker ) {
return - 1 ;
}
}
void testWorker() {
ptrWorker->Image() ;
ptrWorker->Metadata() ;
ptrWorker->Dlink() ;
}
};
int main() {
Foo f;
f.start() ;
f.testWorker() ;
std::cin.get() ;
}
The commented out constructors allows me to add support for Handler2 and Handler3, however is there a way to determine the handler that was passed to the constructor of the Worker class? At present the member functions Metadata, Image and Dlink use the 'callBack' object. I'll need to make a distinction if the user handler passed in another handler - say Handler2
The fact that I need to use enums to implement, what is effectively my own type-system (in the line of a discrimatory union - aka, a variant), is also a sure sign that the design needs a little re-thinking so in that case I'm open for a redesign. Having to have N-1 dummy handlers (ie, at any one time only one handler is being used and the others are just there doing nothing) defined in the class screams confused and low cohesive object model but who knows.
You could implement this using a functor, derived from a virtual base class:
struct CallbackBase
{
// Dummy virtual functions that does nothing
virtual operator()(DataLink const &, Metadata const &, Image const &) {}
virtual operator()(Metadata const &, Image const &) {}
virtual operator()(Image const &) {}
};
class Worker
{
CallbackBase &callback_;
public:
Worker(const CallbackBase &callback)
: callback_(callback)
{ }
void Image()
{
// Do something...
callback_(img);
}
void Metadata()
{
// Do something...
callback_(meta, img);
}
void Dlink()
{
// Do something...
callback_(dlink, meta, img);
}
};
struct MyCallback : public CallbackBase
{
virtual operator()(Image const &)
{
// Do something useful here
}
};
MyCallback my_callback;
Worker my_worker(my_callback);
Because of the overloads in the base callback class, the Worker class can call any of the of them in the correct place, while you only implement the callback you actually need in the derived callback class.
Related
How do I map C++ class concept to C functions osTimerNew() and osThreadNew() ?
How to use a C++ member function as a Keil RTOS2 osTimerNew() and osThreadNew() callback implementation.
Thanks
From an object oriented point of, I would suggest that you are addressing this is the wrong way. There as no direct relationship between a thread and a timer that indicates that they should be a in a single "class" and it is not a matter of mechanistically "mapping" functions to classes. Rather you need to identify the classes - i.e. the things you want to instantiate objects of, and then define the interfaces - the methods that define the functions and capabilities of those objects.
To that end, I would suggest that a thread (or task) and a timer are separate classes. You might create a higher level class of a periodic task that might then by composed and/or derived from these other classes. For example:
or
Let us consider the cTask class to start with. It would be wrong (or at least pointless) to simply wrap the osThreadNew() function in a class wrapper; rather you need to think a a task as a class and consider all the things that class may do. To that end, the CMSIS RTOS reference provides some inspiration in the organisation of its documentation. It has a section on Thread Management and Thread Flags that can be use to design the cTask interface.
A simple task class might have the following interface foir example:
class cTask
{
public:
typedef uint32_t tEventFlags ;
cTask();
virtual ~cTask();
eOSStatus spawn( const char* taskname,
int taskpriority = DEFAULT_PRIORITY,
int stack_size = DEFAULT_STACK, void* stack_ptr = 0 );
void setEvent( tEventFlags flags ) const ;
static void delay(int period);
static void lock();
static void unlock();
int getPriority() const ;
int setPriority(int new_priority);
private :
virtual void threadMain() = 0 ;
tEventFlags eventWait( tEventFlags flags, int timeout ) ;
static void entry_point( void* arg )
{
cTask* instance = reinterpret_cast<cTask*>(argv) ;
instance->threadMain() ;
}
} ;
And you might then have a task:
class cMyThread : cTask()
{
public :
cMyThread()
{
spawn( "mythread" ) ;
}
void someEvent()
{
setEvent( 0x0001 ) ;
}
void someOtherEvent()
{
setEvent( 0x0002 ) ;
}
private:
void threadMain()
{
for(;;)
{
tEventFlags event eventWait( 0x0003, WAIT_FOREVER ) ;
if( (event & 0x0001) != 0 )
{
// process some event
}
if( (event & 0x0002) != 0 )
{
// process some other event
}
}
}
} ;
Such that you might instantiate and communicate with instance od cMyThread thus:
cMyThread thread_a ;
cMyThread thread_b ;
thread_a.someEvent() ;
thread_b.someOtherEvent() ;
Obviously the interface could be much more extensive, and you would want to add classes for semaphores, mutexes, message queues as well as timers.
The above is illustrative only; as you can see there is a lot of work perhaps to be done, but to answer your question osThreadNew()would be used here to implementcTask::spawn()and would start thecTask::threadMain()via the staticentry_point()function by passing it thethis` pointer.
You would take a similar approach to the cTimer class with respec to defining teh interface in terms of things a timer can do. such as start, cancel, wait, set event handler etc.
It is not necessary to slavishly provide an interface to every CMSIS RTOS function; the C++ layer provides an opportunity to abstract some of that detail into something easier to use and easier to port to some other RTOS API.
You give "this" to osTimerNew()/osThreadNew() in place of a "void * argument" parameter.
struct task
{
task ( uint32_t timer_period_ms )
{
// === casting (needs must)
using fp = void ( task::* ) ( void * );
using os_fp = void ( * ) ( void * );
auto cast =
[] ( fp in )
{
union {
fp in;
os_fp out;
} u { in };
return u.out;
};
auto timer_id = osTimerNew
(
cast ( &task::rtos_timer_callback ),
osTimerPeriodic,
this, // let RTOS know about the object
nullptr
);
m_id_thread = osThreadNew
(
cast ( &task::rtos_thread_callBack ),
this, // let RTOS know about the object
nullptr
);
osTimerStart ( timer_id, timer_period_ms );
}
virtual ~task() = default;
virtual void do_work () = 0;
private:
void rtos_timer_callback ( void * pvArg )
{
osThreadFlagsSet ( m_id_thread, 0x01 );
}
__NO_RETURN void rtos_thread_callBack ( void * pvArg )
{
while (1)
{
osThreadFlagsWait ( 0x01, osFlagsWaitAny, osWaitForever );
do_work ();
}
}
private:
osThreadId_t m_id_thread {};
};
Now use the task class:
struct d_task_0 : public task
{
d_task_0 ( uint32_t timer_period_ms ) : task { timer_period_ms } {}
void do_work () final
{
// called every d_task_0::timer_period_ms
}
};
and create another task:
struct d_task_1 : public task
{
d_task_1 ( uint32_t timer_period_ms ) : task { timer_period_ms } {}
void do_work () final
{
// called every d_task_1::timer_period_ms
}
};
And finally create workers:
d_task_0 worker0 { 500 }; // d_task_0::do_work () called every 500ms
d_task_1 worker1 { 800 }; // d_task_1::do_work () called every 800ms
RTOS2 documentation:
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__ThreadMgmt.html
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__TimerMgmt.html
and implementation:
https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/RTOS2
My toolchain: Keil MDK-ARM Plus 5.33.0.0; ArmClang/Link v6.15
Casting solution came from here: Casting between void * and a pointer to member function
Another way of casting is:
using os_fp = void ( * ) ( void * );
void ( task::*pTimer ) ( void * ) = &task::rtos_timer_callback;
void * task_timer = ( void*& ) pTimer;
auto timer_id = osTimerNew
(
reinterpret_cast<os_fp>(task_timer),
osTimerPeriodic,
this, // let RTOS know about the object
nullptr
);
Source:
Get memory address of member function?
In the code bellow I get the error on EXPECTED_CALL(..)
"no matching function for call to 'dia::security::SecurityLevelMock::gmock_acceptEvent()'"
which is weird since I have the method implemented.
Any hint would be appreciated.
class SecurityLevelMock
{
public:
virtual ~SecurityLevelMock( void ) {}
MOCK_METHOD3( acceptEvent, resulttype( statemachine::stateevent event, void* pArg, resulttype initialErrorCode ) ); /*implemented by this class*/
MOCK_METHOD2( acceptEvent, resulttype( statemachine::stateevent event, void* pArg ) ); /*implemented by this class*/
};
class SecurityLevel : public SecurityLevelMock, public std::enable_shared_from_this<SecurityLevel>
{
//...code
}
TEST_F( SecurityLevelAccess_UT, mytest )
{
auto security_level_access_obj = std::make_shared<SecurityLevelAccess>( "val1", p1 , p2, "val2" );
//...
EXPECT_CALL(*(std::shared_ptr<dia::security::SecurityLevelMock>)security_level_access_obj, acceptEvent( ) ).Times( 1 );
}
//file.h
class SecurityLevelAccess : public security::SecurityLevel
{
//code
}
I would like to write a C#-like C++ event class like this :
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
std::vector< ListenerType * >::reverse_iterator revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
void Trigger( const byte_t * pData )
{
for( size_t nI = 0; nI < m_aListeners.size(); ++nI )
m_aListeners[ nI ]->OnDataReceived( pData );
}
}
The problem is that it forces me to write a Trigger method that always does the same thing (iterate and call handlers) for each event type since different events can have a different list of parameter, and for each event, the associated handler type has a mehod with a specific name.
I don't know much about C++11, but i have the feeling that it would be possible to avoid rewritting the Trigger method for each event type using templates.
But i can't use C++11, so i wonder if there is a way, using older C++ version, to do that, in a type safe way.
EDIT : I thought about creating a hierarchy of event data classes, i.e template< typename ListenerType >::Data and DataReceivedEvent::Data : public template< typename ListenerType >::Data so that i can have a Trigger method always taking a single argument, i.e virtual void Trigger( const Data * pData ). But I still have the problem that it needs to call a specific method in the event listener.
You can use templates and operator overloading for this as well. When you assume that the ListenerType implements the operator() you can implement it like this (the example also uses variadic templates. You can use arbitrary amount of arguments):
#include <vector>
#include <iostream>
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
auto revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
template<typename... Params>
void operator()(Params... data) {
for (auto l : m_aListeners) {
(*l)(data...);
}
}
};
class DataReceivedListener {
public:
void operator()(const char* pData) {
std::cout << pData << std::endl;
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
};
int main() {
DataReceivedEvent e;
DataReceivedListener l1;
DataReceivedListener l2;
e += &l1;
e += &l2;
e("Hello");
}
Unfortunately, C++11 does not introduces Concepts. If you had this (constraints in C#) you would get some more help by the compiler.
Is it possible to bind functions with derived parameters ? And if how ? I would like to be able to store function points to various functions that all have a similar signature, namely they take a class with input data and return a class with output values. But the different functions require and provide different parameters, hence I am trying to register functions that take derived message classes.
The following code works in part. I can register the function MathService::blank and I can later call it. But I cannot add MathService::add.
The error I get is:
main.cpp:70:93: error: conversion from ‘std::_Bind_helper&)(RequestMessage&, ReplyMessage&), MathService&, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind(MathService*, std::_Placeholder<1>, std::_Placeholder<2>)>}’ to non-scalar type ‘Service::serviceFunction_t {aka std::function}’ requested
serviceFunction_t fn = bind( methodPtr, objectPtr, placeholders::_1, placeholders::_2 );
#include <functional>
#include <unordered_map>
#include <iostream>
using namespace std;
// base class for messages passed around
class BaseMessage
{
public:
virtual void print()
{
cout << "BaseMessage\n";
}
};
// request message with data passed to the service
class RequestMessage : public BaseMessage
{
public:
RequestMessage( int a_, int b_ ) : a( a_ ), b( b_ ) {}
int a;
int b;
void print()
{
cout << "RequestMessage a=" << a << " b=" << b << endl;
}
};
// reply message with return values from the service
class ReplyMessage : public BaseMessage
{
public:
ReplyMessage() : sum( 0 ) {}
int sum;
void print()
{
cout << "ReplyMessage sum=" << sum << endl;
}
};
// Example service provider
class MathService
{
public:
void blank( BaseMessage& request, BaseMessage& reply )
{
request.print();
reply.print();
}
void add( RequestMessage& request, ReplyMessage& reply )
{
reply.sum = request.a + request.b;
}
};
// Class manages services, register a new service with addService and call the service by name using call
class Service
{
public:
using serviceFunction_t = function<void ( BaseMessage&, BaseMessage& )>;
template<class Method, class Obj>
void addService( string name, Method methodPtr, Obj objectPtr )
{
serviceFunction_t fn = bind( methodPtr, objectPtr, placeholders::_1, placeholders::_2 );
pair< string, serviceFunction_t> entry( name, fn );
mFunctionMap.insert( entry );
}
void call( const string& name, BaseMessage& request, BaseMessage& reply )
{
std::unordered_map<string, serviceFunction_t>::const_iterator it;
it = mFunctionMap.find( name );
if( it == mFunctionMap.end() ) {
std::cout << "service not found: " << name << endl;
return;
}
serviceFunction_t fn = it->second;
fn( request, reply );
}
private:
unordered_map<string, serviceFunction_t> mFunctionMap;
};
int main()
{
MathService math;
Service service;
// can add a service with BaseMessages
service.addService( "blank", &MathService::blank, &math );
//*****************************************************
// PROBLEM is here !!
// can not add a service with derived message types, this causes the bind call to fail in Service::addService()
service.addService( "add", &MathService::add, &math );
//*****************************************************
// this works
BaseMessage req1, rep1;
service.call( "blank", req1, rep1 );
// so does this
RequestMessage req2( 1, 2 );
ReplyMessage rep2;
service.call( "blank", req2, rep2 );
// this service is not registered
service.call( "add", req2, rep2 );
}
1) do is a reserved C++ keyword, so your code as-this will never compile
2) std::placeholders_1 does not exist, you surely meant std::placeholders::_1
3) Once this is fixed, yes, it compiles.
I am trying to implement a class that would allow listening on some events and when these emits are emitted, they would get notifications.
So i thought of using Functors,
class MyFunctor {
public:
virtual void emit() {}
vitual void compare() {}
};
class MyFunctorSpecial : public MyFunctor {
void (*)() ab;
public:
MyFunctorSpecial(void (*a)()) : ab(a) {}
void emit() { ab(); }
};
class EventEmitter {
std::map<std::string, std::vector<MyFunctor> > eventMap;
public:
void On(const std::string &, const MyFunctor &) {
// add to the map
}
void Emit(const std::string & eventName) {
// emit the event
// for all listeners in the vector for this event-name
// call the emit of them.
}
};
EventEmitter emitter;
// some function - abc()
MyFunctorSpecial funct(abc);
emitter.On("hello", funct);
emitter.Emit("hello");
But now i want to pass arguments to the listeners. Like
emitter.Emit("hello", 45, false);
I think that this information would be available to Emit() at compile time, about the data-types of the various arguments. Can i use that information to make it happen , using templates or anything.
If there is another kind of pattern for this problem? How can I do this?
The common design pattern for your problem is called the Observer Design-Pattern.
Your so called "functors" are not functors.
If so they would have implemented an operator () method, and could have been called like functions ( thus the name functor). Yours are not.
For example, this is a functor: ( notice the operator())
class MyFunctor
{
public:
void operator()(){};
};
try this simple example as follow:
class event_manager {
std::map<std::string, std::vector<std::function<void( std::string )>>> eventMap;
public:
void on( const std::string &evt_name, std::function<void( std::string )> listener ) {
auto it = eventMap.find( evt_name );
if ( it != eventMap.end( ) ) {
it->second.push_back( listener );
return;
}
eventMap[evt_name] = std::vector<std::function<void( std::string )>>( );
eventMap[evt_name].push_back( listener );
};
void emit( const std::string &evt_name, std::string data ) {
auto evts = eventMap.find( evt_name );
if ( evts == eventMap.end( ) ) return;
for ( std::vector<std::function<void( std::string )>>::iterator it = std::begin( evts->second ); it != std::end( evts->second ); ++it ) {
auto &func = *it;
func( data );
}
}
};
and subscribe and emit event as like:
event_manager evt_mng;
evt_mng.on( "data", [&]( auto res ) {
std::cout << res << std::endl;
} );
evt_mng.emit( "data", "Hello world" );