Turning a struct or class into a component and use it’s methods

There are two fundamental ways to do this:
  • Do it the basic way

  • Additionallly wrap the client side of things into a wrapper object to have typesafety and ease of mind

In this tutorial I’m doing it the dumb way without a client object, because that needs to be done anyways and such is always the first thing to do.

Step 1: Define your object and component actions in the header file

////////////////////////////
// Component Library Header
// myObj.hpp
/* Boilerplate: Includes, etc ... */

namespace app {

  struct HPX_EXPORT_COMPONENT myObj : PUBLIC hpx::components::component_base<myObj> {

    string sayHello();
    // Variant 1: Let the macro chose a default name for the action ("sayHello_action" in this case)
    HPX_DEFINE_COMPONENT_ACTION(myObj, sayHello);

    string sayGoodBye(string sender);
    // Variant 2: Chose a custom name for the action ("sayGoodBye_a" in this case)
    HPX_DEFINE_COMPONENT_ACTION(myObj, sayGoodBye, sayGoodBye_a); // chosing a custom action name

    // We are not exposing this method as an action;
    void setName(string name);

    private:
    string name_ = "Nobody";

  };
  // Variant A: Inside the namespace:
  // In this case the action will be known globally as app::myobj_component_sayHello_action
  HPX_REGISTER_ACTION_DECLARATION ( myObj::sayHello_action, myobj_component_sayHello_action );
};

// Variant B: Outside the namespace
HPX_REGISTER_ACTION_DECLARATION ( app::myObj::sayGoodBye_a, myobj_component_sayGoodBye_a );

Step 2: Implement your methods in the source and add additional Macros to announce the component and the actions to HPX

////////////////////////////
// Component Library
// myObj.cpp
/* Boilerplate: Includes, etc ... */

string app:myObj::sayHello(){
    return "Hello ! I am " + (this->name_);
}
string app:myObj::sayGoodBye(string sender){
    return "Bye " + sender + "!";
}
void setName(string name){
    this->name_ = name;
}

// Announce everything to HPX:
// 1. Needed for all components
HPX_REGISTER_COMPONENT_MODULE ( );

// 2. myObj component
using myObj_component      = app::myObj;
using myObj_component_type = hpx::components::component<app::myObj>;
HPX_REGISTER_COMPONENT ( myObj_component_type, myObj_component );

// 3. myObj component actions
// These must match HPX_REGISTER_ACTION_DECLARATION in the header
HPX_REGISTER_ACTION ( app::myObj::sayHello_action, app::myobj_component_sayHello_action );
HPX_REGISTER_ACTION ( app::myObj::sayGoodBye_a,         myobj_component_sayGoodBye_a    );

Step 3: Use your component and actions in your HPX Application

 ////////////////////////////
 // Application Header
 // File: MyApp.hpp
 /* Boilerplate: Includes, etc ... */

 #include "myObj.hpp"

/* other code ... */
// This is really a very limited example ...
// get our local locality id
hpx::id_type here = hpx::find_here ( );
// async + remote class instantiation (in this example: remote==local)
hpx::future<hpx::id_type> fut = hpx::new_<app::myObj> ( here );
// get new app::myObj instance id and wait for it if necessary
hpx::id_type mObjId = fut.get ( );
// start the sayHello Action on our object
auto rFut = hpx::async<app::myObj::sayHello_action> ( mObjId );
// wait for hello to finish and return a result
cout << "Hello from new object: " << rFut.get ( ) << endl;

/* other code ... */