Best workaround for compiler error C2158: make_public does not support native template types - c++-cli

I have two c++/cli dlls (i.e. compiled with /clr) where A.dll references B.dll. In assembly B, I have a method, GetMgdClassB, I'd like to call from assembly A. Here is the code in assembly B (B.cpp):
namespace B
{
public class NativeClassB
{
public:
NativeClassB();
// ...
};
public ref class MgdClassB
{
public:
static MgdClassB ^ GetMgdClassB(const std::vector<NativeClassB *> & vecNativeBs)
{
// ...
vecNativeBs;
return gcnew MgdClassB();
}
};
}
Notice that the method GetMgdClassB takes a std::vector. In assembly A, I attempt to call this method with the following code (A.cpp):
namespace B
{
class NativeClassB;
}
#pragma make_public(std::vector<B::NativeClassB *>)
namespace A
{
void Foo()
{
std::vector<B::NativeClassB *> vecNativeBs;
B::MgdClassB::GetMgdClassB(vecNativeBs);
}
}
When I compile A.cpp, I get the following error:
error C2158: 'std::vector<_Ty>' : #pragma make_public directive is currently supported for native non-template types only
the reason I wanted to add this pragma is because native types are private to the assembly by default. If I remove the pragma I get the following error (as expected):
error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible
since the template instantiation type std::vector<B::NativeClassB *> is private to the assembly.
Attempted Solutions
1. Use void *, break type safety:
Change the method, GetMgdClassB to take a void * and pass the address of the std::vector<NativeClassB *> to the method. In GetMgdClassB. I can then static_cast the passed in void * to std::vector<NativeClassB *> *. This, of course, works, but breaks type safety.
2. Create a Managed wrapper for NativeClassB, pass a managed container
Create a managed class, say ref class NativeClassBWrapper who's sole purpose is to hang on to a reference to the native NativeClassB. Change GetMgdClassB to take a managed container of NativeClassBWrappers (e.g. List<NativeClassBWrapper ^> ^). This has the downside of having to create and populate a new managed container prior to calling GetMgdClassB, and then within managed class B, I have to repackage it into the the native container std::vector<NativeClassB *> (since the code in B deals with this type.
Currently, I'm leaning toward going with Solution #1, since (a) it doesn't introduce any performance concerns and (b) I'll only be doing this in a few cases. I don't like losing the type safety, but it seems justifiable given the current deficiency in the compiler's ability to make native template instantiation types visible.
Question:
Are there better work arounds?
Related Question:
C++ CLI error C3767: candidate function(s) not accessible

I'm not aware of any way to export that type. If you have to have that function signature, I would lean in the direction of using a mix of managed and native exports (managed functions using native types can't be consumed by other languages anyway), and maybe use delay loading when calling the native exports so you have a chance to trap errors finding the assembly in the usual .NET way.
But your particular function may be problematic since it uses both managed types and complex native types in the signature.
In general, the best practice is to not pass native C++ classes across DLL boundaries at all, since this sets you up for One Definition Rule violations.
For this particular situation, my suggestion is to make an wrapper that implements ICollection. That cures the problem just like your solution #2, without ever having to actually copy all the elements into a new data structure.

I received a solution from Mike Danes on another forum:
http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/b43cca63-b0bf-451e-b8fe-74e9c618b8c4/
Basically, the solution is to create a native wrapper (call it VectorOfNativeB) in assembly B that holds on to a pointer or reference to the std::vector. Export VectorOfNativeB and make it publicly visible. Change method GetMgdClassB to take a pointer or reference VectorOfNativeB.
[posted this here for future reference and to see if anyone here has any comments about this solution].

Related

Dlang: why are constructors not inherieted?

Is there a way to not have to repeatidly write this(parent class args) {super(parent class args);} when the arguments are exactly the same?
The code:
class Parent {
string name;
this(string name) {
this.name = name;
}
}
class Child : Parent {
}
unittest {
auto child = new Child("a name");
assert(child.name == "a name");
}
https://run.dlang.io/is/YnnezI
Gives me the compilation error:
Error: class onlineapp.Child cannot implicitly generate a default constructor when base class onlineapp.Parent is missing a default constructor
Java and C# don't inherit constructors either (unless that's changed in the last few years - I don't think C++ allowed it either until c++11), and D follows the same reasoning so you can read more by looking up things about them.
Basically though the reason is that subclasses must have their own unique state - at very least stuff like the vtable even if you don't declare any of your own variables - and thus a unique constructor is required. Otherwise you can have uninitialized members.
And if inheritance went the whole way, since Object has a this(), new AnyClass(); would compile and lead to a lot of invalid objects. (In regular D, if you declare any ctor with arguments, it disables the automatically-generated zero arg one.)
Now, D could in theory do what C++ does and auto-generate other args too... it just doesn't. Probably mostly because that is a relatively new idea in C++ and D's class system is primarily based on Java's older system.
But all that said, let me show you a trick:
this(Args...)(auto ref Args args) { super(args); }
stick that in your subclass and you basically inherit all the parent's constructors in one go. If the super doesn't compile for the given args, neither will this, so it doesn't add random things either. You can overload that with more specific versions if needed too, so it is a reasonable little substitute for a built-in language feature.

Accepting managed struct in C++/CLI both with "hat" operator and without. What is the difference?

I've got a C++/CLI layer that I've been using successfully for a long time. But I just discovered something that makes me think I need to relearn some stuff.
When my C++/CLI functions receive an instance of any managed class, they use the "hat" operator ('^') and when they receive an instance of a managed struct, they do not. I thought this was how I was supposed to write it.
To illustrate as blandly as I can
using Point = System::Windows::Point;
public ref class CppCliClass
{
String^ ReturnText(String^ text) { return text; } // Hat operator for class
Point ReturnStruct(Point pt) { return pt; } // No hat operator for struct
};
I thought this was required. It certainly works. But just today I discovered that CancellationToken is a struct, not a class. My code accepts it with a hat. I thought it was a class when I wrote it. And this code works just fine. My cancellations are honored in the C++/CLI layer.
void DoSomethingWithCancellation(CancellationToken^ token)
{
// Code that uses the token. It works just fine
}
So apparently I can choose either method.
But then what is the difference between passing in a struct by value (as I've done with every other struct type I use, like Point) and by reference (as I'm doing with CancellationToken?). Is there a difference?
^ for reference types and without for value types matches C#, but C++/CLI does give you more flexibility:
Reference type without ^ is called "stack semantics" and automatically tries to call IDisposable::Dispose on the object at the end of the variable's lifetime. It's like a C# using block, except more user-friendly. In particular:
The syntax can be used whether the type implements IDisposable or not. In C#, you can only write a using block if the type can be proved, at compile time, to implement IDisposable. C++/CLI scoped resource management works fine in generic and polymorphic cases, where some of the objects do and some do not implement IDisposable.
The syntax can be used for class members, and automatically implements IDisposable on the containing class. C# using blocks only work on local scopes.
Value types used with ^ are boxed, but with the exact type tracked statically. You'll get errors if a boxed value of a different type is passed in.

Why can't I extend the static Math class?

I'm working on an ActionScript 2 project that relied on some extensions to the Math class, usually done as such:
Math.sinD = function(angle) {
return Math.sin(angle*(Math.PI/180));
};
Allowing a caller to just write (for example)
Math.sinD(60);
However, when I try to compile with just the original line, I get the following error:
There is no property with the name "sinD".
Why isn't this working, and more importantly, how can I make it work again?
To my mind looks impossible.
Create static sinD method in separate class.
The 'problem' lies with ActionScript 2's static type checking. You can't directly modify a class because it checks that the property you're trying to access exists. However, you can do it if you bypass the type checking:
var Math2 = Math; // thing now holds a reference to the same Math class, but with no type set
// Add a new method
Math2.sinD = function(angle) {
return Math.sin(angle*(Math.PI/180));
};
// Now the Math has 'sinD' as a method
Or alternatively... (these both do the same thing)
Math['sinD'] = function(angle) {
return Math.sin(angle*(Math.PI/180));
};
However, this doesn't really help, because the static type checking is enforced at the calling places as well, so you can access any dynamically added methods.
Math.sinD(30) // This will not compile
Instead, you need to do:
var Math2 = Math;
Math2.sinD(30) // returns 0.5
Math['sinD'](30); // also returns 0.5
At which point, you may as well just create your own class rather than modifying the existing class.
Fortunately, for my case this means that there aren't any usages of these extensions (at least not statically typed usages), so I should be able to safely delete the extensions and not worry about it :)

Why don't protected C++-Cli destructors cause compilation errors?

If I compile and run the following:
using namespace System;
ref class C1
{
public:
C1()
{
Console::WriteLine(L"Creating C1");
}
protected:
~C1()
{
Console::WriteLine(L"Destroying C1");
}
};
int main(array<System::String ^> ^args)
{
C1^ c1 = gcnew C1();
delete c1;
return 0;
}
...the code compiles without an error and runs giving me this:
Creating C1
Destroying C1
Press any key to continue . . .
If I do the same in C++ I get an error along the following lines:
1>ProtectedDestructor.cpp(45): error C2248: 'C1::~C1' : cannot access protected member declared in class 'C1'
1> ProtectedDestructor.cpp(35) : compiler has generated 'C1::~C1' here
1> ProtectedDestructor.cpp(23) : see declaration of 'C1'
...so why is it valid in CLI?
This is a leaky abstraction problem. C++/CLI has several of them, we already went through the const keyword problem. Much the same here, the runtime does not have any notion of a destructor, only the finalizer is real. So it has to be faked. It was pretty important to create that illusion, the RAII pattern in native C++ is holy.
It is faked by bolting the notion of a destructor on top of the IDisposable interface. The one that makes deterministic destruction work in .NET. Very common, the using keyword in the C# language invokes it for example. No such keyword in C++/CLI, you use the delete operator. Just like you would in native C++. And the compiler helps, automatically emitting the destructor calls when you use stack semantics. Just like a native C++ compiler does. Rescuing RAII.
Decent abstraction, but yes, it leaks. Problem is that an interface method is always public. It is technically possible to make it private with explicit interface implementation although it is but a stopgap:
public ref class Foo : IDisposable {
protected:
//~Foo() {}
virtual void Dispose() = IDisposable::Dispose {}
};
Produces a very impressive error list when you try this, the compiler fights back as hard as it can :). C2605 is the only relevant one: "'Dispose': this method is reserved within a managed class". It can't maintain the illusion when you do this.
Long story short, the IDisposable::Dispose() method implementation is always public, regardless of the accessibility of the destructor. The delete operator invokes it. No workaround for this.
In addition to Hans's detailed answer that delete on a C++/CLI object is actually activation of the IDisposable interface, and interface inheritance is always public1, it may be fruitful to ask
How does the protected destructor get called, then?
The compiler-generated Dispose methods call the user-defined destructor. Because this Dispose method is a member of the class, it has access to protected and private class members, such as the destructor.
(In native C++, the compiler isn't subject to accessibility rules, since it is the one enforcing them. In .NET, the IL verifier enforces them.)
1 Actually, his explanation centers on the fact that the compiler doesn't allow explicit implementation of IDisposable::Dispose(), in which case it could be a private member. But that's completely irrelevant. virtual members can be reached through the declaring type. And delete doesn't call object->Dispose(), it calls safe_cast<IDisposable^>(object)->Dispose().

Sharing `Static` Methods Between Classes in a Single File in Objective-C

I am baffled by a static method whose definition apparently lives in one class, but whose declaration is shared between several classes in the same file. Can it be shared between files somehow?
The Details
I'm trying to divide a .mm file into several files (one per class). All of the source code is from Pete Goodliffe's CoreMIDI Example.
I took the PGMidi class from here and busted it up into separate interfaces and classes. Everything compiles perfectly except for one method marked static, which needs to be in two places at once (it's "used but never defined" in PGMidi). The method is "used" in this line outside of any class implementation:
static void PGMIDIReadProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
which is apparently shared by all classes in the same file (what?). It's mentioned in two classes.
1) In PGMidi, where it's used (perhaps pointing to PGMidiSource
s = MIDIInputPortCreate(client, (CFStringRef)#"MidiMonitor Input Port", PGMIDIReadProc, self, &inputPort);
2) In PGMidiSource, where the method body is defined
static
void PGMIDIReadProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon)
{
PGMidiSource *self = (PGMidiSource*)srcConnRefCon;
[self midiRead:pktlist];
}
The problem is that the self referred to in the method body makes no sense in PGMidi (no midiRead method)...
What is this static method? How I can get it to work between two files?
The static function is just a normal C function. The 'static' means it can only be accessed from within the same file. So you need to either:
Redefined it for every file you want use it from, typically by putting the entire static function definition in a header and include the header in every file you want to use it, or
Make it a non-static function and put the function prototype in a header, then include the header in every file you want to use it from.
On a function, the static keyword roughly means "only visible and usable from within this file". Since it was defined in PGMidiSource.mm, you cannot call it from PGMidi.mm. Luckily, this is fairly easy to fix.
Declare the function prototype in PGMidiSource.h, like this:
void PGMIDIReadProc(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
Remove the static keyword in PGMidiSource.mm, since it needs to be usable from outside that file.
Note that this is not a "method"; it is a C function. As such, it belongs to no class, is not tied to any instance, has no access to any instance variables, etc. Any context that it needs must be passed in as a parameter. Hence, while this function uses a variable called "self", it's actually just a local alias for one of the parameters that was passed in.
The reason that it looks like that "method" is shared between multiple classes is because it's not technically a method. Instead, that's a C function. You can add C to Objective C in that manner, and that particular function can be invoked from multiple files, though it's a good practice to provide a "prototype" in a header file for the files that don't have the actual function implemented within them. (Or it was the last time I wrote in C. It's been a while.)
If you don't provide the prototype in the other files, C will let you go merrily on your way (though the compiler will probably say it doesn't know anything about that function in a warning.) But the linker will resolve it, and assuming it's coded correctly, it should work.