How to implement generic read() and write() methods using C++ templates
Note: This article applies to RTI Connext DDS 4.5f and above and relates to the Traditional C++ API. Since 5.0.0 the Modern C++ API provides better support for generic programming.
RTI Connext 4.5f added support for the use of C++ traits on each top level type generated by rtiddsgen. In this solution we illustrate how to create write() and read() methods for any DataWriter or DataReader using C++ templates.
Generic write() method
For every top-level type, rtiddsgen adds a set of typedefs (traits) that allow referring to their related DataWriter, DataReader, TypeSupport and Sequence types. For a given type T, typename T::DataWriter identifies its DataWriter type. For example, for type Foo, Foo::DataWriter is FooDataWriter.
template <typename T>
DDS_ReturnCode_t my_generic_write(typename T::DataWriter *writer, const T &instance_data, DDS_InstanceHandle_t instance_handle)
{
DDS_ReturnCode_t retcode;
retcode = writer->write(instance_data, instance_handle);
return retcode;
}
To invoke this generic write method in your publisher application, change the write() method call by my_generic_write() method, and specify the type that needs to be instantiated between angle brakets (e.g., <hello>):
hello *instance = NULL;
DDS_InstanceHandle_t instance_handle = DDS_HANDLE_NIL;
// ...
/* Main loop */
for (count=0; (sample_count == 0) || (count < sample_count); ++count)
{
printf("Writing hello, count %d\n", count);
/* Modify the data to be sent here */
retcode = my_generic_write<hello>(hello_writer, *instance, instance_handle)
if (retcode != DDS_RETCODE_OK) {
printf("write error %d\n", retcode);
}
NDDSUtility::sleep(send_period);
}
Generic read() method
If you want to define a generic read() method, you can implement the following take_and_print() method:
template <typename T>
void take_and_print(typename T::DataReader* reader)
{
DDS_SampleInfo info;
T * sample = T::TypeSupport::create_data();
DDS_ReturnCode_t result = reader->take_next_sample(*sample, info);
if (result == DDS_RETCODE_OK && info.valid_data) {
T::TypeSupport::print_data(sample);
}
T::TypeSupport::delete_data(sample);
}
To invoke this method in your subscriber application, i.e., to read samples of type Foo and Bar, call take_and_print() as follows:
FooDataReader *foo_datareader = ...;
BarDataReader *bar_datareader = ...;
take_and_print<Foo>(foo_datareader);
take_and_print<Bar>(bar_datareader);