RTI Connext Modern C++ API Version 7.3.0
DynamicType and DynamicData Use Cases

Using DynamicType and DynamicData.

Using DynamicType and DynamicData.

The following #includes are needed for the examples on this page

#include <dds/core/ddscore.hpp>
#include <dds/pub/ddspub.hpp>
#include <dds/sub/ddssub.hpp>
#include "Foo.hpp"

Creating a DynamicType

In this section we'll see the different ways to create a dds::core::xtypes::DynamicType
that represents the following IDL type MyType:

struct Foo {
long x; //@key
long y;
};
struct MyType {
long my_long;
string<512> my_string;
Foo my_foo;
sequence<long, 10> my_sequence;
Foo my_array[5];
Foo my_optional; //@Optional
};
An example topic-type.
Definition: types.dxx:34

Create a DynamicType by instantiating it and adding members

(Note this example uses C++11 code that can easily be converted to similar C++03 code)

{
using namespace dds::core::xtypes;
// First, let's create Foo. We're using an initializer_list of Members
StructType foo(
"Foo", {
Member("x", primitive_type<int32_t>()).key(true),
Member("y", primitive_type<int32_t>())
}
);
// Create MyType and add members
StructType mytype("MyType");
mytype.add_member(Member("my_long", primitive_type<int32_t>()));
mytype.add_member(Member("my_string", StringType(512)));
mytype.add_member(Member("my_foo", foo));
mytype.add_member(Member("my_sequence", SequenceType(primitive_type<int32_t>(), 10)));
mytype.add_member(Member("my_array", ArrayType(foo, 5)));
mytype.add_member(Member("my_optional", foo).optional(true));
return mytype;
}
<<value-type>> Represents and IDL struct type
Definition: StructTypeImpl.hpp:34
dds::core::optional< T > optional
Optional type according to the IDL4-C++ OMG specification. Alias of dds::core::optional.
Definition: optional.hpp:37
Contains the types and functions to support Extensible Types.
Definition: dds/core/corefwd.hpp:54
void print_idl(const DynamicType &type, unsigned int indent=0)
<<extension>> Prints the IDL representation of this DynamicType to the standard output

Create a DynamicType from an XML description

We can define the type in this XML file, MyType.xml:

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://community.rti.com/schema/current/rti_dds_profiles.xsd">
<types>
<struct name= "Foo">
<member name="x" type="int32" key="true"/>
<member name="y" type="int32"/>
</struct>
<struct name= "MyType">
<member name="my_long" type="int32"/>
<member name="my_string" stringMaxLength="512" type="string"/>
<member name="my_foo" type="nonBasic" nonBasicTypeName= "Foo"/>
<member name="my_sequence" sequenceMaxLength="10" type="int32"/>
<member name="my_array" type="nonBasic" nonBasicTypeName= "Foo" arrayDimensions="5"/>
<member name="my_optional" type="nonBasic" nonBasicTypeName= "Foo" optional="true"/>
</struct>
</types>
</dds>

And then load it as follows:

using namespace dds::core::xtypes;
// Create a QosProvider (or use the default one)
dds::core::QosProvider qos_provider("path/to/MyType.xml");
// Get the type called MyType
const DynamicType& mytype = qos_provider.extensions().type("MyType");
// Downcast to StructType if needed
const StructType& mytype_struct = static_cast<const StructType&>(mytype);
<<reference-type>> The QosProvider class provides a way for a user to control and access the XML QoS ...
Definition: TQosProvider.hpp:162
See also
Qos Provider Use Cases

Get the DynamicType from its equivalent IDL-generated type

<<extension>> When we have the IDL type definition at hand, obtaining its equivalent DynamicType is as simple as:

Provides a DynamicType that represents an IDL-generated type.
Definition: rti/topic/TopicTraits.hpp:165

Create a DynamicType using tuples

<<C++11>> <<experimental>> <<extension>> Note this code requires the additional header <rti/core/xtypes/DynamicDataTuples.hpp>.

Since this feature only supports structures containing primitive types or strings, we'll create the following simpler IDL type:

struct MyOtherType {
long m1;
double m2;
string m3;
};

We can create the type in a single line:

int32_t, double, std::string>("MyOtherType");
basic_string< char, rti::core::memory::OsapiAllocator< char > > string
A string convertible to std::string and with similar functionality.
Definition: String.hpp:266
dds::core::xtypes::StructType create_type_from_tuple(const std::string &name)
<<C++11>> <<experimental>> <<extension>> Creates a StructType from a list of types or a std::tuple
Definition: DynamicDataTuples.hpp:232

For convenience, we can also use a std::tuple, which allows us to typedef it:

typedef std::tuple<int32_t, double, std::string> MyOtherTypeTuple;
mytype = rti::core::xtypes::create_type_from_tuple<MyOtherTypeTuple>("MyOtherType");

Using DynamicData

Now that we know how to create a DynamicType, we will see how to use DynamicData to publish and subscribe to data that we can manipulate reflectively.

We will use the DynamicType that we created before.

Publishing data using DynamicData

Make sure you are already familiar with the regular publication example.

Unlike the regular publication example, using dynamic data we can write code where the type is unknown at compilation type.

using namespace dds::core::xtypes;
StructType mytype = create_mytype(); // create the type as we saw before
// The template parameter is DynamicData. The third argument is the
// DynamicType, instead of the type name.
dds::topic::Topic<DynamicData> topic(participant, "MyTopic", mytype);
// Create a data sample and assign its values
DynamicData sample(mytype);
sample.value("my_long", 23); // my_long = 23
sample.value<std::string>("my_string", "hello"); // my_string = hello
// To set my_foo we have two options:
// 1) Create a new DynamicData and assigning it:
// We can get the DynamicType of Foo from MyType::my_foo
DynamicData foo_data(mytype.member("my_foo").type());
foo_data.value("x", 1);
foo_data.value("y", 2);
sample.value("my_foo", foo_data);
// 2) Obtain the loaned member and assign its values
rti::core::xtypes::LoanedDynamicData loaned_member = sample.loan_value("my_foo");
loaned_member.get().value("x", 2);
loaned_member.get().value("y", 3);
loaned_member.return_loan(); // The destructor would do this as well.
// To set the values of my_sequence we can use a vector
std::vector<int32_t> sequence_values;
sequence_values.push_back(10);
sequence_values.push_back(20);
sequence_values.push_back(30);
sample.set_values("my_sequence", sequence_values);
// To set the values of my_array, since the element type is another struct
// we will use a LoanedDynamicData to access the array elements. To modify
// each element we will use another LoanedDynamicData
loaned_member = sample.loan_value("my_array");
rti::core::xtypes::LoanedDynamicData array_element = loaned_member.get().loan_value(1);
array_element.get().value("x", 10);
array_element.get().value("y", 11);
loaned_member.get().loan_value(array_element, 2); // reuse array_element
array_element.get().value("x", 20);
array_element.get().value("y", 21);
array_element.return_loan();
loaned_member.return_loan();
// We're not setting the remaining 3 elements, so they will have default values
// We manipulate optional members as regular members. By setting a value
// we are implicitly asserting its presence in the sample.
sample.value("my_optional", foo_data);
// This is how we can unset it:
sample.clear_optional_member("my_optional");
// Finally we just write the sample
writer.write(sample);
std::cout << sample << std::endl;
const MemberType & member(MemberIndex index) const
Gets a member by its index.
<<reference-type>> Container for all dds::core::Entity objects.
Definition: TDomainParticipant.hpp:63
<<reference-type>> Allows an application to publish data for a dds::topic::Topic
Definition: TDataWriter.hpp:58
<<reference-type>> A publisher is the object responsible for the actual dissemination of publications...
Definition: TPublisher.hpp:52
<<reference-type>> Topic is the most basic description of the data to be published and subscribed.
Definition: TTopic.hpp:56
<<move-only-type>> Gives temporary access to a member of another DynamicData object.
Definition: DynamicDataImpl.hpp:962
void return_loan()
Explicitly returns the loan.
DynamicData & get()
Obtains the loaned DynamicData object representing a member of DynamicData object.
Definition: DynamicDataImpl.hpp:989

Subscribing to data using DynamicData

using namespace dds::core::xtypes;
using namespace rti::core::xtypes;
using namespace std; // for cout and endl
StructType mytype = create_mytype(); // create the type as we saw before
// The template parameter is DynamicData. The third argument is the
// DynamicType, instead of the type name.
dds::topic::Topic<DynamicData> topic(participant, "MyTopic", mytype);
// ...
// Read/take samples normally
dds::sub::LoanedSamples<DynamicData> samples = reader.take();
for (auto sample : samples) {
if (sample.info().valid()) {
DynamicData& data = const_cast<DynamicData&>(sample.data());
cout << data.value<int32_t>("my_long") << endl;
// To inspect a complex member we can get a copy of it:
DynamicData foo_copy = data.value<DynamicData>("my_foo");
cout << foo_copy.value<int32_t>("x") << endl;
// Or a loan:
LoanedDynamicData loaned_member = data.loan_value("my_foo");
cout << loaned_member.get().value<int32_t>("y") << endl;
loaned_member.return_loan(); // Note: the destructor also returns the loan if needed
// Note that we could have taken advantage of the destructor to save
// the call to return_loan:
cout << data.loan_value("my_foo").get().value<int32_t>("y") << endl;
// To get the values of my_sequence we can use a vector:
std::vector<int32_t> sequence_values = data.get_values<int32_t>("my_sequence");
// We could also have reused a vector:
data.get_values("my_sequence", sequence_values);
// To get the values of my_array, since the element type is another
// struct we will use a LoanedDynamicData to access the array
// elements.
loaned_member = data.loan_value("my_array"); // Note: this move-assignment only works in C++11
for (size_t i = 1; i <= loaned_member.get().member_count(); i++) {
LoanedDynamicData array_element = loaned_member.get().loan_value(i);
cout << array_element.get().value<int32_t>("x") << endl;
cout << array_element.get().value<int32_t>("y") << endl;
}
// When getting an unset optional member, value() will throw
// dds::core::InvalidArgumentError, but we can check if it's set:
if (data.member_exists("my_optional")) {
foo_copy = data.value<DynamicData>("my_optional");
cout << foo_copy.value<int32_t>("x") << endl;
cout << foo_copy.value<int32_t>("y") << endl;
} else {
cout << "my_optional is not set" << endl;
}
}
}
<<reference-type>> Allows the application to: (1) declare the data it wishes to receive (i....
Definition: TDataReader.hpp:74
<<move-only-type>> Provides temporary access to a collection of samples (data and info) from a DataRe...
Definition: LoanedSamplesImpl.hpp:77
<<reference-type>> A subscriber is the object responsible for actually receiving data from a subscrip...
Definition: TSubscriber.hpp:49
<<extension>> Extensions to dds::core::xtypes
Definition: rti/core/corefwd.hpp:69

Manipulating data reflectively using C++ tuples

<<C++11>> <<experimental>> <<extension>>

This feature allows publishing and subscribing to simple data types without code generation and directly using C++ types instead of the DynamicData getters and setters.

This is an example publisher:

using namespace dds::core::xtypes;
// Create the type
int32_t, double, std::string>("MyType");
// Create participant, topic and writer
dds::topic::Topic<DynamicData> topic(participant, "MyTopic", mytype);
// Create a data sample and assign its values
DynamicData sample(mytype);
sample, std::make_tuple(10, 50.5, std::string("Hello")));
// Write the sample
writer.write(sample);
std::cout << sample << std::endl;
void set_tuple(dds::core::xtypes::DynamicData &data, const std::tuple< Types... > &value)
<<C++11>> <<experimental>> <<extension>> Assigns the values of a std::tuple to a DynamicData object a...
Definition: DynamicDataTuples.hpp:149

And this is a subscriber:

using namespace dds::core::xtypes;
using namespace rti::core::xtypes;
// Create the type
int32_t, double, std::string>("MyType");
dds::topic::Topic<DynamicData> topic(participant, "MyTopic", mytype);
// Read/take samples normally
dds::sub::LoanedSamples<DynamicData> samples = reader.take();
for (auto sample : samples) {
if (sample.info().valid()) {
// We obtain a std::tuple from the DynamicData sample
int32_t, double, std::string>(sample.data());
std::cout << std::get<0>(my_tuple) << std::endl;
std::cout << std::get<1>(my_tuple) << std::endl;
std::cout << std::get<2>(my_tuple) << std::endl;
}
}
std::tuple< Types... > get_tuple(const dds::core::xtypes::DynamicData &data)
<<C++11>> <<experimental>> <<extension>> Retrieves all the values of a DynamicData object into an std...
Definition: DynamicDataTuples.hpp:96