|
open62541pp 0.21.2
C++ wrapper of open62541
|
Open62541pp provides two separate extension points for working with types that are not built into OPC UA:
Choose the one that matches your situation. They can also be combined.
Use opcua::TypeConverter when your C++ type has a natural mapping to one of the OPC UA built-in types (e.g. UA_Byte, UA_Int32, UA_Float). Defining a specialization enables opcua::Variant to accept and return your type transparently via assign() and to<T>(). No new OPC UA type is introduced on the wire; the existing built-in type is used for encoding.
Specialization contract:
Both functions should be [[nodiscard]]. Use value parameters for primitive types (UA_Byte, UA_Int32, …) and const-reference parameters for non-primitive types.
Example — mapping std::byte to UA_Byte:
After this specialization, std::byte is a first-class citizen in opcua::Variant:
Use opcua::DataTypeBuilder when your data is a composite type (structure, union, or enumeration) that needs its own OPC UA type identity and binary encoding. This is the correct approach when the server exposes a structured type that the client must deserialize, or when you publish your own structured variables.
The C++ struct passed to opcua::DataTypeBuilder must have a C-compatible memory layout:
std::vector, std::string, …). Use the open62541 convention for dynamic arrays: a size_t count field immediately followed by a T* pointer field (see the Measurements example in examples/custom_datatypes/).nullptr pointer means the field is absent.Describe the binary layout of your C struct using opcua::DataTypeBuilder. The resulting opcua::DataType object must be kept alive for the lifetime of the server or client that uses it.
Structure:
Enumeration — the C++ enum must have an underlying type of int32_t:
Union:
The two NodeId arguments to create* are the type's node id and its binary encoding node id in the OPC UA information model. These must match the IDs used in the server's address space.
Before starting the server or connecting the client, register all custom type descriptions via the config:
Always pass the opcua::DataType when constructing a opcua::Variant from a custom type:
When reading, inspect the type before casting:
ExtensionObject elements. See examples/custom_datatypes/client_custom_datatypes.cpp for a worked example.TypeConverter and DataTypeBuilder address orthogonal concerns and can be used together. For example, you can add a TypeConverter that maps std::filesystem::path to UA_String, and independently define a custom OPC UA structure that contains a UA_String field.
You can also add an opcua::TypeRegistry specialization so that template-deduced Variant construction works without repeating the DataType argument:
| Question | Use |
|---|---|
| Map my C++ type to an existing UA built-in | TypeConverter |
| Define a new composite type encoded over the wire | DataTypeBuilder |
Use variant.to<T>() with a custom DataType | TypeRegistry |
| Server exposes a structure I need to read | DataTypeBuilder + addCustomDataTypes |