Registering Nested Component Actions
Expected Behavior
I'm attempting to convert an established MPI code to HPX by writing an HPX version of the program's swappable communication submodule. I've been following along with the local to remote example in the documentation. I'm preserving most of the structure from the distributed memory verson of that example and trying to nest it in a class of the type being used for the communication submodule.
Actual Behavior
When running the example below as is, mimicking the local to remote example with an extra layer of indirection to the components, I get an error about the get_data_action that I registered using HPX_DEFINE_COMPONENT_DIRECT_ACTION() not naming a type:
error: ‘get_data_action’ in ‘struct CommHPX::partition_server’ does not name a type
763 | typedef CommHPX::partition_server::get_data_action get_data_action;
| ^~~~~~~~~~~~~~~
Trying to make CommHPX inherit hpx::components::component_base<> in the same manner as the partition_server component and adding a matching call to HPX_REGISTER_COMPONENT() as shown below throws a long list of errors regarding multiple definitions. I think I'm either fundamentally misunderstanding nested components or trying to leverage a code structure that HPX doesn't support.
typedef hpx::components::component<CommHPX> comm_hpx_type;
HPX_REGISTER_COMPONENT(comm_hpx_type, CommHPX)
Steps to Reproduce the Problem
This is a stripped down version of the class structure of the communication module, as well as the macros I'm using to register the components and actions in global scope.
comm_hpx.h
class CommHPX {
struct partition_data {}
struct partition_server : hpx::components::component_base<partition_server> {
partition_data get_data() const;
}
struct partition : hpx::components::client_base<partition, partition_server> {}
}
HPX_DEFINE_COMPONENT_DIRECT_ACTION(CommHPX::partition_server, get_data, get_data_action)
typedef hpx::components::component<CommHPX::partition_server> partition_server_type;
HPX_REGISTER_COMPONENT(partition_server_type, partition_server)
typedef CommHPX::partition_server::get_data_action get_data_action;
HPX_REGISTER_ACTION(get_data_action)
comm_hpx.cpp
hpx::future<CommHPX::partition_data> CommHPX::partition::get_data() const {
get_data_action act;
//return hpx::async(act, get_id(), t);
return hpx::async(act, get_id());
}
Specifications
- HPX Version: 1.8
- Platform (compiler, OS): CMake/3.21.1, GCC/8.3.0, Arch
I tried to reproduce your issue by composing the code you provided (with some minor modifications). Everything seems to work as expected:
#include <hpx/hpx_main.hpp>
#include <hpx/modules/async_distributed.hpp>
#include <hpx/modules/runtime_components.hpp>
class CommHPX
{
public:
struct partition_data
{
};
struct partition_server : hpx::components::component_base<partition_server>
{
partition_data get_data() const
{
return {};
}
};
struct partition : hpx::components::client_base<partition, partition_server>
{
using client_base::client_base;
hpx::future<CommHPX::partition_data> get_data() const;
};
};
using partition_server_type =
hpx::components::component<CommHPX::partition_server>;
HPX_REGISTER_COMPONENT(partition_server_type, partition_server)
HPX_DEFINE_COMPONENT_DIRECT_ACTION(
CommHPX::partition_server, get_data, get_data_action)
HPX_REGISTER_ACTION(get_data_action)
hpx::future<CommHPX::partition_data> CommHPX::partition::get_data() const
{
get_data_action act;
return hpx::async(act, get_id());
}
int main()
{
CommHPX::partition const p = hpx::local_new<CommHPX::partition>();
hpx::wait_all(p.get_data());
return 0;
}