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);