Declaration
template<class ContainerType,
bool IsOnlyMovable = cobalt::marshalling::internal::is_only_movable<typename cobalt::marshalling::internal::get_last_nested_container_element_type<ContainerType>::type>::value>
class Ret;Description
The Marshal::Ret class is a helper class designed to allow largely transparent and automatic marshalling of types as return values from functions. Through appropriate use, implicit conversions in the Marshal::Ret type allow identical code to be written by the caller whether marshalling is employed or not. Unlike other marshal helper classes, the Marshal::Ret helper class always needs to perform one allocation of heap memory in order to operate, making it marginally less efficient than values returned through arguments using the Marshal::Out helper.
Note that the Marshal::Ret template type makes use of template specialization to change its implementation based on the specific type supplied in its first template argument, and the characteristics of that type. As such, its list of members varies based on the type supplied.
Members
Constructors (varies between specializations)
| Name | Description | |
|---|---|---|
| Ret |
Constructs the marshaller and binds the return value
|
Marshal methods (varies between specializations)
| Name | Description | |
|---|---|---|
| Get |
Marshals the bound element to a new object, performing a move if possible.
|
|
| GetWithoutMove |
Marshals the bound element to a new object, leaving the original object unchanged.
|
Conversion operators
| Name | Description | |
|---|---|---|
| operator ContainerType() |
Performs an implicit conversion from the marshaller to the native type. Note that unlike the Marshal::In helper, a move is performed by an implicit conversion where possible.
|
Examples
Recommended usage
Given the following code without any marshalling involved:
std::vector<int> SomeFunction()
{
std::vector<int> result;
result.push_back(1);
return result;
}
int main()
{
std::vector<int> result = SomeFunction(arg);
std::cout << arg.back() << std::endl;
return 0;
}
The recommended conversion to use marshalling would take this form:
Marshal::Ret<std::vector<int>> SomeFunction()
{
std::vector<int> result;
result.push_back(1);
return result;
}
int main()
{
std::vector<int> result = SomeFunction();
std::cout << result.back() << std::endl;
return 0;
}
Note that the syntax remains unchanged for the caller, making it relatively easy to add marshalling to existing APIs. The return value is adapted to use marshalling simply by wrapping it in a Marshal::Ret helper.
String conversion example
Given the following code without any marshalling involved:
std::string SomeFunction()
{
return "SomeValue";
}
int main()
{
std::string result = SomeFunction();
std::cout << result << std::endl;
return 0;
}
The code can be converted to marshal the string argument by changing the function signature alone, as follows:
Marshal::Ret<std::string> SomeFunction()
{
return "SomeValue";
}
int main()
{
std::string result = SomeFunction();
std::cout << result << std::endl;
return 0;
}
In this case, implicit conversions handle the conversion from string literals to our marshal helper.
Using std::move on return
There is an important difference in behaviour here between C++11 compilers, and those conforming to the C++14 standard or higher, regarding whether returned values will be treated as movable or not by default. According to the rules as defined in the C++11 standard, implicit conversions of local objects being returned from a function via the return keyword will not treat the source object as movable by default, even though it is going out of scope. An explicit std::move operation would be required in order to allow moving the source object in these cases. This means that in our previous example function, as shown here:
Marshal::Ret<std::vector<int>> SomeFunction()
{
std::vector<int> result;
result.push_back(1);
return result;
}
On a C++11 compiler, this will in fact invoke the constructor for Marshal::Ret using a const lvalue reference. In order to bind to the return value as a non-const rvalue reference, we would need to use std::move on the returned value, as follows:
Marshal::Ret<std::vector<int>> SomeFunction()
{
std::vector<int> result;
result.push_back(1);
return std::move(result);
}
This was a limitation of the C++11 language specification, and it was addressed in Defect Report 1579, the changes for which were adopted into the C++14 language. If you are using a C++14 conforming compiler or higher, a move will automatically be performed where appropriate. If you are using C++11 however, be aware that as per the C++11 language rules, a move operation cannot be generated automatically in this case, and you may need to perform an std::move operation on returned values when adapting them for marshalling in order to achieve the best possible performance, or to support move-only types.