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 Ttypename T::DataWriter identifies its DataWriter type. For example, for type FooFoo::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);

 

Programming Language: