Page 1 of 1

Using Y_BEHAVIOR_METHOD2 with classes with inheritence

Posted: 23 Oct 2018, 08:18
by Milad
Hi,
I have a question about using Y_BEHAVIOR_METHOD2 with a class that has inheritance.
First of all, I have to ask if it is possible to use Y_BEHAVIOR_METHOD2 macro with classes with several layers of inheritance and call functions from the parent and any of the children?
If yes then how should the address of the method be provided to the macro?
If no is there any other way to solve the problem?

Thanks a lot in advance for your time and answer.

Re: Using Y_BEHAVIOR_METHOD2 with classes with inheritence

Posted: 07 Dec 2018, 13:42
by Wolfgang Petroschka
Hi Milad,

sorry, that it took actually ages to answer your questions. But we have been super busy...

First of all, I have to ask if it is possible to use Y_BEHAVIOR_METHOD2 macro with classes with several layers of inheritance and call functions from the parent and any of the children?
Yes, it is. But it is not very pretty syntactically.

If yes then how should the address of the method be provided to the macro?
The name of the method is not the problem. You can pass it as &base::method or as &derived::method no difference. The problem is the object pointer (the first parameter). You have to cast your pointer outside the macro to the according class.

Code: Select all

Base* bp = static_cast<Base*>(this);
and then you can use the casted pointer within the macro.
It's ugly, but it works.

Code: Select all

Layer1* l1 = static_cast<Layer1*>(this); sxy::simple_state& simple_state_replying = main_region.add_simple_state( "replying", Y_BEHAVIOR_METHOD2( l1, &Layer1::reply ) )

I created a quick and dirty example based on "Hello, yasmine!" for you:

Code: Select all

////////////////////////////////////////////////////////////////////////////////////////////////////// // // // This file is part of the Seadex yasmine ecosystem (http://yasmine.seadex.de). // // Copyright (C) 2016-2018 Seadex GmbH // // // // Licensing information is available in the folder "license" which is part of this distribution. // // The same information is available on the www @ http://yasmine.seadex.de/Licenses.html. // // // ////////////////////////////////////////////////////////////////////////////////////////////////////// #include <iostream> #include "libyasmine/include/yasmine.hpp" const sxy::event_id HELLO_EVENT = 1; class Layer1 { public: void reply() { std::cout << "Hello, yasmine!" << std::endl; } }; class Layer2 : public Layer1 { public: void wait() { std::cout << "waiting" << std::endl; } }; class Layer3 : public Layer2 { public: Layer3(): error_code_(0), hello_yasmine_state_machine_() { hello_yasmine_state_machine_ = setup_state_machine( "hello yasmine state machine" ); if( check_state_machine_for_defects( *hello_yasmine_state_machine_ ) ) { hello_yasmine_state_machine_->run(); try { hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) ); hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) ); hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) ); hello_yasmine_state_machine_->halt(); } catch( const std::exception& exception ) { SX_LOG( hermes::log_level::LL_FATAL, "Unhandled exception: '%'.", exception.what() ); error_code_ = 1; } catch( ... ) { SX_LOG( hermes::log_level::LL_FATAL, "Unknown exception!" ); error_code_ = 2; } } else { error_code_ = 3; } } int get_error_code() const { return error_code_; } private: typedef sxe::SX_UNIQUE_PTR< sxy::sync_state_machine > state_machine_uptr; state_machine_uptr setup_state_machine( const std::string& _name ) { Layer1* l1 = static_cast<Layer1*>(this); Layer2* l2 = static_cast<Layer2*>(this); state_machine_uptr state_machine = SX_MAKE_UNIQUE< sxy::sync_state_machine >( _name ); sxy::composite_state& root_state = state_machine->get_root_state(); sxy::region& main_region = root_state.add_region( "main region" ); sxy::initial_pseudostate& initial_pseudostate = main_region.add_initial_pseudostate( "initial" ); sxy::simple_state& simple_state_waiting = main_region.add_simple_state( "waiting", Y_BEHAVIOR_METHOD2( l2, &Layer2::wait ) ); sxy::simple_state& simple_state_replying = main_region.add_simple_state( "replying", Y_BEHAVIOR_METHOD2( l1, &Layer1::reply ) ); state_machine->add_transition( HELLO_EVENT, simple_state_waiting, simple_state_replying ); state_machine->add_transition( sxy::Y_COMPLETION_EVENT_ID, initial_pseudostate, simple_state_waiting ); state_machine->add_transition( sxy::Y_COMPLETION_EVENT_ID, simple_state_replying, simple_state_waiting ); return( state_machine ); } bool check_state_machine_for_defects( const sxy::sync_state_machine& _state_machine ) { sxy::state_machine_defects defects; const bool state_machine_has_no_defects = _state_machine.check( defects ); if( !state_machine_has_no_defects ) { sxy::write_defects_to_log( defects ); } return( state_machine_has_no_defects ); } int error_code_; state_machine_uptr hello_yasmine_state_machine_; }; int main() { #ifndef SX_NO_LOGGING hermes::log_manager_template<hermes::std_timestamp_policy>& log_manager = hermes::log_manager::get_instance(); log_manager.set_log_level( hermes::log_level::LL_FATAL ); log_manager.add_logger( SX_MAKE_UNIQUE< hermes::cout_logger >() ); log_manager.run(); sxy::version::log_version(); #endif Layer3 layer3; #ifndef SX_NO_LOGGING log_manager.halt_and_join(); #endif return( layer3.get_error_code() ); }

Re: Using Y_BEHAVIOR_METHOD2 with classes with inheritence

Posted: 07 Dec 2018, 13:43
by Wolfgang Petroschka
The board software removed the line breaks in the code, so here for now without code tags:

//////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// This file is part of the Seadex yasmine ecosystem (http://yasmine.seadex.de). //
// Copyright (C) 2016-2018 Seadex GmbH //
// //
// Licensing information is available in the folder "license" which is part of this distribution. //
// The same information is available on the www @ http://yasmine.seadex.de/Licenses.html. //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////


#include <iostream>

#include "libyasmine/include/yasmine.hpp"


const sxy::event_id HELLO_EVENT = 1;

class Layer1 {
public:
void reply()
{
std::cout << "Hello, yasmine!" << std::endl;
}

};

class Layer2 : public Layer1 {
public:
void wait()
{
std::cout << "waiting" << std::endl;
}
};

class Layer3 : public Layer2 {
public:

Layer3():
error_code_(0),
hello_yasmine_state_machine_()
{
hello_yasmine_state_machine_ = setup_state_machine( "hello yasmine state machine" );

if( check_state_machine_for_defects( *hello_yasmine_state_machine_ ) )
{
hello_yasmine_state_machine_->run();
try
{
hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) );
hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) );
hello_yasmine_state_machine_->fire_event( sxy::event_impl::create( HELLO_EVENT ) );
hello_yasmine_state_machine_->halt();
}
catch( const std::exception& exception )
{
SX_LOG( hermes::log_level::LL_FATAL, "Unhandled exception: '%'.", exception.what() );
error_code_ = 1;
}
catch( ... )
{
SX_LOG( hermes::log_level::LL_FATAL, "Unknown exception!" );
error_code_ = 2;
}
}
else
{
error_code_ = 3;
}
}

int get_error_code() const
{
return error_code_;
}

private:
typedef sxe::SX_UNIQUE_PTR< sxy::sync_state_machine > state_machine_uptr;

state_machine_uptr setup_state_machine( const std::string& _name )
{
Layer1* l1 = static_cast<Layer1*>(this);
Layer2* l2 = static_cast<Layer2*>(this);
state_machine_uptr state_machine = SX_MAKE_UNIQUE< sxy::sync_state_machine >( _name );
sxy::composite_state& root_state = state_machine->get_root_state();
sxy::region& main_region = root_state.add_region( "main region" );
sxy::initial_pseudostate& initial_pseudostate = main_region.add_initial_pseudostate( "initial" );
sxy::simple_state& simple_state_waiting = main_region.add_simple_state( "waiting", Y_BEHAVIOR_METHOD2( l2, &Layer2::wait ) );
sxy::simple_state& simple_state_replying = main_region.add_simple_state( "replying", Y_BEHAVIOR_METHOD2( l1, &Layer1::reply ) );
state_machine->add_transition( HELLO_EVENT, simple_state_waiting, simple_state_replying );
state_machine->add_transition( sxy::Y_COMPLETION_EVENT_ID, initial_pseudostate, simple_state_waiting );
state_machine->add_transition( sxy::Y_COMPLETION_EVENT_ID, simple_state_replying, simple_state_waiting );

return( state_machine );
}

bool check_state_machine_for_defects( const sxy::sync_state_machine& _state_machine )
{
sxy::state_machine_defects defects;
const bool state_machine_has_no_defects = _state_machine.check( defects );
if( !state_machine_has_no_defects )
{
sxy::write_defects_to_log( defects );
}

return( state_machine_has_no_defects );
}

int error_code_;
state_machine_uptr hello_yasmine_state_machine_;
};

int main()
{
#ifndef SX_NO_LOGGING
hermes::log_manager_template<hermes::std_timestamp_policy>& log_manager = hermes::log_manager::get_instance();
log_manager.set_log_level( hermes::log_level::LL_FATAL );
log_manager.add_logger( SX_MAKE_UNIQUE< hermes::cout_logger >() );
log_manager.run();
sxy::version::log_version();
#endif

Layer3 layer3;

#ifndef SX_NO_LOGGING
log_manager.halt_and_join();
#endif

return( layer3.get_error_code() );
}

Re: Using Y_BEHAVIOR_METHOD2 with classes with inheritence

Posted: 04 Feb 2019, 10:32
by Milad
Great, Thank you very much for your answer.