How to use optional with a managed type - c++-cli

I want to create a function where there might be an exception and return optional if that's the case.
Here is a little code sample.
optional<Exception^> opt;
if (opt)
MessageBox::Show("Error");
I get the following errors:
Error C3265 cannot declare a managed '_Value' in an unmanaged
'std::_Optional_destruct_base<_Ty,false>::$UnnamedClass$0x61d94762$23$' CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 87
Error C2848 'std::_Optional_destruct_base<_Ty,false>::_Value': a
managed type cannot be a member of a
union CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 87
Error C3699 '&&': cannot use this indirection on type
'_Ty' CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 431
Error C3699 '&&': cannot use this indirection on type 'const
_Ty' CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 435
Error C3699 '&&': cannot use this indirection on type
'_Ty' CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 467
Error C3699 '&&': cannot use this indirection on type 'const
_Ty' CLR d:\visualstudio\vc\tools\msvc\14.16.27023\include\optional 476
So how can I use optional? Is it possible at all in C++ CLI? What are the alternatives?

My understanding of std::optional is that it's a value type that might not contain a value because something failed. The .Net standard way of dealing with a failure of this type is to throw an exception or to let an exception propagate out. However, it sounds like you don't want to do this, so here's the alternatives.
For a .Net reference type (declared in C# as class, in C++/CLI as ref class or ref struct, used in C++/CLI with the ^), the way to deal with this is simply to return nullptr. Reference types are very, very rarely stored by value, and returning null is much more standard.
For a .Net value type (declared in C# as struct, in C++/CLI as value class or value struct, used in C++/CLI without the ^), I would use System::Nullable<T>. Nullable is a type similar to Optional, where a value type is allowed to be null.

Related

Primitve Boxing StackManipulation

There seems to be a difference in the implementation of PrimitiveBoxingDelegate and PrimitiveUnboxingDelegate.
Basically I would like to box a primitive value on the stack, so it can be returned as a reference (ie. the method returns Object)
PrimitiveUnboxingDelegate.forPrimitive() provides me with a StackManipulation but unfortunately PrimitiveBoxingDelegate.forPrimitive() does not.
Is there an easy way to create a boxing StackManipulation?
You can, you just need to specify the type to which the value should be boxed to what is implicit for unboxing:
StackManipulation sm = PrimitiveBoxingDelegate
.forPrimitive(...)
.assignBoxedTo(..., Assigner.DEFAULT, Assigner.Typing.STATIC);
You can cast an int to for example a Object or a Number. You can however create illegal combinations as well what is sometimes necessary for Byte Buddy's own purposes.

What is the point of CTypeDynamic?

I'm using reflection to serialize an object. Getting the values as objects is a real murder on performance due to late binding penalties. CType / DirectCast can get rid of most of it but I can't feed a type variable into it so currently I'm using a switch case block on the type variable to select the correct DirectCast.
It came to my attention that CTypeDynamic exists and takes type variables but the return type is Object so... it converts an object into an object, cool. That got me wondering, what is the purpose of this function?
The CTypeDynamic function looks for dynamic information and performs the cast/conversion appropriately. This is different from the CType operator which looks for static information at compile time or relies on the types being IConvertible.
This function examines the object at runtime including looking for Shared (aka static) custom operators. As always, if you know the type then use CType, but if you need dynamic casting then you need to use CTypeDynamic.
More information here: http://blogs.msmvps.com/bill/2010/01/24/ctypedynamic/

Which is the correct form for a C++-CLI copy constructor?

I have some code like this:
MyClass::MyClass(MyClass^ objToCopyFrom);
Which is producing an error:
'type' : ref class does not have a user-defined copy constructor
When I look up the error, it suggests my code should look like this:
MyClass::MyClass(MyClass% objToCopyFrom);
My question is therefore, which version is correct or are they both correct?
Only your second version is correct:
MyClass::MyClass(MyClass% objToCopyFrom);
or its variant:
MyClass::MyClass(const MyClass% objToCopyFrom);
MyClass% is a so-called Tracking Reference which is the conceptual equivalence of a reference in native C++, only for CLR types.
While copy constructors in native C++ can have a number of different signatures, what they all have in common is that the other object that's being copied is passed in as a reference. C++/CLI stays close to that principle, but uses its own type of object references, a tracking reference.

CLI/C++ function overload

I am currently writing a wrapper for a native C++ class in CLI/C++. I am on a little GamePacket class at the moment. Consider the following class:
public ref class GamePacket
{
public:
GamePacket();
~GamePacket();
generic<typename T>
where T : System::ValueType
void Write(T value)
{
this->bw->Write(value);
}
};
I want that I'm able to call the function as following in C#, using my Wrapper:
Packet.Write<Int32>(1234);
Packet.Write<byte>(1);
However, I can't compile my wrapper. Error:
Error 1 error C2664: 'void System::IO::BinaryWriter::Write(System::String ^)' : cannot convert argument 1 from 'T' to 'bool'
I don't understand this error, where does the System::String^ comes from. I'm seeing a lot of overloads of the Write() method, does CLI/C++ not call the correct one, and if so, how can I make it call the correct one?
Reference MSDN: http://msdn.microsoft.com/en-us/library/system.io.binarywriter.write(v=vs.110).aspx
Templates and generics don't work the same.
With templates, the code gets recompiled for each set of parameters, and the results can be pretty different (different local variable types, different function overloads selected). Specialization makes this really powerful.
With generics, the code only gets compiled once, and the overload resolution is done without actually knowing the final parameters. So when you call Write(value), the only things the compiler knows is that
value can be converted to Object^, because everything can
value derives from ValueType, because your constraint tells it
Unfortunately, using just that information, the compiler can't find an overload of Write that can be used.
It seems like you expected it to use Write(bool) when T is bool, Write(int) when T is int, and so on. Templates would work like that. Generics don't.
Your options are:
a dozen different copies of your method, each of which has a fixed argument type that can be used to select the right overload of BinaryWrite::Write
find the overload yourself using reflection, make a delegate matching the right overload, and call it
use expression trees or the dynamic language runtime to find and make a delegate matching the right overload, and then you call it

How to convert from C# ref type to CLI\C++ ^% type

I am writing an application in Managed C++ (CLI\C++). In which I am using a library (.dll file) which is written in C#.
In a file I am encountering a problem.
I am implementing functions of an interface which is written in the library.
The declaration of a function in the library is as given below:
COMWORKSPACELib.IWorkspaceEvents.WorkspaceMessage(int, string, COMWORKSPACELib.EnumNotificationCode, COMWORKSPACELib.EnumNotificationType, string, ref COMWORKSPACELib.EnumNotificationReply);
When I write the same code in CLI\C++ the declaration is like:
WorkspaceMessage(int workspaceToken, String ^description, EnumNotificationCode ^code, EnumNotificationType ^type, String ^source, EnumNotificationReply ^%action);
Here, the compiler is giving me error that the “class must provide an implementation for the interface method”. Because the parameters passed in both function declarations are syntactically different.
Is there any alternative way to match the library declaration?
If I remove the “^’ & ‘%’ to match the library declaration then it gives further errors in the code.
Are EnumNotifcationCode, EnumNotificationType, and EnumNotficationReply all enums? That is, are they value types? If so, then it should be declared as follows:
WorkspaceMessage(int workspaceToken,
String^ description,
EnumNotificationCode code,
EnumNotificationType type,
String^ source,
EnumNotificationReply% action);