How to marshal following native C++ objects to C++/CLI? - interop

I am a bit confused on how to marshal below mentioned C++ object to c++/CLI. Could you give me some idea?
Native C++ Classes
class HeaderMessage {
double timestamp;
string ric_code;
}
class TradeMessage {
double price;
int size;
}
class RFARecord
{
public:
RFARecord();
HeaderMessage * hMsg;
list<TradeMessage *> qMsgs;
};
My C++/CLI classes look like this
public ref class RFARecordRef
{
public:
RFARecordRef();
RFARecordRef(RFARecord *record);
HeaderMessageRef hMsg;
List<TradeMessageRef> tMsgs;
private:
RFARecord *record;
};
ref class HeaderMessageRef
{
private:
HeaderMessage *hMsg;
public:
HeaderMessageRef(void);
};
ref class TradeMessageRef
{
private:
TradeMessage *tMsg;
public:
TradeMessageRef(void);
};
I am not sure if my approach is correct.
I read data from a text file and transfer this data in the form of RFARecords to my C# program.
What is the right way to wrap or marshal above data objects to C++/CLI which can then be consumed by my C# program.
Thanks in advance.
Regards,
Alok

If I understand correctly. Your biggest task is going to be marshaling the strings from c++ strings into System::String^ objects.
What your going to do is declare a method in the C++/CLI class that returns a type System::String^ like so:
System::String^ get_str_from_cpp()
{
std::string str = ptr_to_native_cpp_class->get_str();
System::String^ ret_str = std_str2sys_str(str);
return ret_str;
}
The std_str2sys_str method looks like so.
static System::String^ std_str2sys_str(std::string std_str)
{
System::String^ sys_str = gcnew System::String(std_str.c_str());
return sys_str;
}
Of course you could use a char* to if you wanted to.
The "ptr_to_native_cpp_class" variable should be a class variable that points to an instance of your native c++ class. It appears you already have those.
There are also ways to marshal from the System::String^ to std::string or char* which are on the net. Hopefully this example helps though. You don't have to worry about marshalling basic types like ints or bools though, you can just return them directly from your C++/CLI layer to the C#.
To answer the question of marshalling an structure over to C++/CLI; I don't think there is a way to automatically marshal an entire custom structure, even if it is composed completely of basic types. What I do in my code is just write a wrapper object that has specific get methods for each data member like so:
//Native C++ class
class data_container
{
public:
int var1;
int var2;
}
//C++/CLI class
public ref class cli_data_container
{
public:
get_var1() {return data_ptr->var1;}
get_var2() {return data_ptr->var2;}
private:
data_container* data_ptr;
};
If there is an automatic way to do this that would be nice, but we had an intern make these interfaces for us for a few dozen utility classes last summer and they get the job done.

Related

C++: convert not from obj1 to obj2, but from obj1* to obj2?

A constructor for MyClass takes a pointer to another such object.
The C++ MyClass is functionally the same as a C "class" based on a typedef'd struct called MyType_T. (The C++ class is basically a wrapper to the old C code.) I'd like to be able to pass in a MyClass* anywhere I could pass in a MyType_T* before.
I'd like to write an automatic conversion of any MyClass* to MyType_T*, but I guess what's throwing me is that my type converter is written to take a MyClass not a MyClass*. Even though I'm sure that's the problem, I can't think of what syntax would solve it. I've thought about making a friend implementation of the cast, but I can't put it before the definition of class MyClass because it won't know the offset of thing. And I can't put after the definition of class MyClass because the MyClass constructor wants to use that conversion.
typedef struct MyStruct {
int iFoo;
struct MyType* ptypeParent;
} MyType_T;
void MyTypeCreator( MyType_T* ptypeSelf, int iFoo_in, MyType_T* ptypeParent );
class MyClass {
public:
MyClass( int iFoo, MyClass* pclassParent ) {
MyTypeCreator( &thing, iFoo, pclassParent ); <--------------- PROBLEM
MyTypeCreator( &thing, iFoo, &pclassParent->thing ); <------- WORKS
};
operator MyType_T*() { return &thing; } <---------------- INCORRECT: attempts to convert MyClass, not MyClass*, to MyType_T*.
MyType_T thing;
};
QUESTION 1: how to write a convertor from MyClass* instead of MyClass?
QUESTION 2: how can such a convertor check for NULL input? (If thing isn't offset of 0, but say 8, then converting from a NULL pclass without a check would give a value of 0x00000008, not NULL...)

How to call a class function which only argument is &

Here's my code:
class Patient {
public:
const int patientId;
const PatientKind kind;
const bool hasInsurance;
std::vector<ProcedureKind> procedures;
Patient(int, PatientKind, bool);
bool addProcedure(const ProcedureKind procedure);
double billing();
virtual double liability() = 0;
};
class Hospital {
public:
Patient &addPatient(const PatientInfo &);
};`
I don't know how to write:
Patient &Hospital::addPatient(const PatientInfo &)
{
}
Whatever I try to return or pass as argument gives me an error... Also, I don't understand what is this function expecting as an argument with just &?
Any kind of help / insight will be appreciated :D
Seems like you're trying to implement a header definition someone else wrote. That & means that the function expects a reference to an instance of PatientInfo. In the implementation, the only thing you have to do is to give the parameter a name like so:
Patient& addPatient(const PatientInfo& info)
{
// do whatever you need with 'info'
}
You can read more about c++ function declaration and implementation in any basic c++ text.

C++: template class inheritance with variable-type parameters using parameter packs

(I had no idea how to name this question and I couldn't find anything similar. Sorry if this is duplicate)
If I want to inherit from some base template class, I can do this that way:
template<typename A=int, typename B=char> class C {};
template<typename... Args> class D : public C<Args...> {}; //it works!
This way I can change in project passed parameters to template class C and I don't have to change every usage of class D. Great. But what if I have template class using not only types as parameters but also values? For example:
template<int dim=3, typename float_t=double> class GeometricObject{};
template<typename... Args> class Point : public GeometricObject<Args...>{}; //it doesnt work
Of course I could define last template with integer type on the beginning. But this is not a way, if I would have 100 different classes all inheriting from GeometricObject and then I would change default dim value to 2, I would have to change every single class definition.
I also hope that there is the way without using any #define, #else and similar preprocessor commands. I know that templates are in fact also preprocessor commands, but... well, let's be modern here ;)
You can not mix type and non-type parameters in a template parameter pack. But it seems that your Point and other derived classes don't need to access the parameter pack arguments separately. In such cases it's easier, as well as more semantically correct, to pass the base class:
template<int dim=3, typename float_t=double> class GeometricObject{};
template<class GeometricObject=GeometricObject<>> class Point : public GeometricObject{};
Instantiating a Point could then look like:
Point<> a{}; // the same as Point<GeometricObject<>> a{};
Point<GeometricObject<4>> b{};
Point<GeometricObject<2, float>> c{};
Of course the GeometricObject<...> could be typedef'd to something shorter. Also, it can be made to look like a namespace instead of providing parameters to each geometric object separately:
template<int dim = 3, typename float_t = double>
struct GeometricObjects {
using Base = GeometricObject<dim, float_t>;
using Point = ::Point<Base>;
// ...
};
using TwoDim = GeometricObjects<2>;
TwoDim::Point a{};
I suppose you have multiple template classes and you want your Point object to be able to inherit from them all.
Instead of doing:
template <typename ... Args>
class Point : public GeometricObject<Args...>{};
I would instead do:
template <typename T>
class Point : public T {};
Now we just have to define proper traits to access the types template parameters in case they are needed. These types should be factored into a std::tuple (for instance).
The burden to fill this trait is on the GeometricObject class. For example, with your definition we would have:
template <typename T>
struct type_parameters;
template <int N, typename Float>
struct type_parameters<GeometricObject<N, Float> {
typedef std::tuple<Float> types;
};
The main scenario: a method of Point needs the type template parameters of GeometricObject (to forward them to a method of GeometricObject). To achieve this, you will have to pass in a tuple that will be unfold to call the inner method. To do so I make use of features added in the STL for C++14. You could still rewrite them yourself but I spared me the hassle for this question...
template <typename T>
class Point : public T {
template <typename Method, typename ... Args, std::size_t ... Is>
auto call_unfold(Method method, std::tuple<Args...> const& tuple, std::integer_sequence<std::size_t, Is...>) {
return (this->*method)(std::get<Is>(tuple)...);
}
template <typename Method, typename Tuple>
auto call_unfold(Method method, Tuple const& tuple) {
return call_unfold(method, tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
public:
typedef typename type_parameters<T>::types types;
void some_method(types const& args) {
return call_unfold(&T::some_method, args);
}
};
This example is quite meaningless but the same technique could be useful with constructors of Point that need to call a base class constructor.
A live demo showing how it works is available on Coliru
Ok, so I figured it out how I should include variable-type template parameters into tuples. Basically I need to 'encapsulate' them into new parameter. This example works perfectly well AND solves my problem:
#include <type_traits>
template<int n = 2> struct Dim {
const int dim = n;
};
template<typename T> class SillyBaseClass {
public:
typedef typename T dim;
};
template<typename... Args> class SillyDerivedClass : public SillyBaseClass<Args...>{
public:
typedef typename SillyBaseClass::dim dim;
SillyDerivedClass() {
static_assert(std::is_same<dim,Dim<2>>::value,
"Number of dimensions must be equal to 2");
}
};
int main() {
SillyDerivedClass<Dim<2>> Class2d; //this works
SillyDerivedClass<Dim<3>> Class3d; //this returns expected error
}

Enum values as parameter default values in Haxe

Is there a way to use enum default parameters in Haxe? I get this error:
Parameter default value should be constant
enum AnEnum {
A;
B;
C;
}
class Test {
static function main() {
Test.enumNotWorking();
}
static function enumNotWorking(e:AnEnum = AnEnum.A){}
}
Try Haxe link.
Update: this feature has been added in Haxe 4. The code example from the question now compiles as-is with a regular enum.
Previously, this was only possible if you're willing to use enum abstracts (enums at compile time, but a different type at runtime):
#:enum
abstract AnEnum(Int)
{
var A = 1;
var B = 2;
var C = 3;
}
class Test3
{
static function main()
{
nowItWorks();
}
static function nowItWorks(param = AnEnum.A)
{
trace(param);
}
}
There's nothing special about the values I chose, and you could choose another type (string, or a more complex type) if it better suits your use case. You can treat these just like regular enums (for switch statements, etc.) but note that when you trace it at runtime, you'll get "1", not "A".
More information: http://haxe.org/manual/types-abstract-enum.html
Sadly enums can't be used as default values, because in Haxe enums aren't always constant.
This piece of trivia was on the old website but apparently hasn't made it into the new manual yet:
http://old.haxe.org/ref/enums#using-enums-as-default-value-for-parameters
The workaround is to check for a null value at the start of your function:
static function enumNotWorking(?e:AnEnum){
if (e==null) e=AnEnum.A;
}
Alternatively, an Enum Abstract might work for your case.

C++/CLI - Error C2664 again

I am dealing with following problem. To be formal I am using VS2010 Ultimate and I try to write an windows forms application, but I get specified error:
1>f:\baza danych\baza\baza\Form5.h(475): error C2664: 'Bazadanych::Dodaj1' : cannot convert parameter 1 from 'Car' to 'Car'
1> Cannot copy construct class 'Car' due to ambiguous copy constructors or no available copy constructor
and here are Car.h where I have declaration of this class
public ref class Car
{
public:
String^ category;
String^ model;
String^ rocznik;
String^ cena;
Car(){};
Car(String^ ,String^ ,String^ );
void edytuj(String^ ,String^ ,String^ );
String^ getmodel(){return this->model;};
String^ getrocznik(){return this->rocznik;};
String^ getcena(){return this->cena;};
virtual String^ getcat()
{
this->category="To rent";
return this->category;
};`
}
Definition:
Car::Car(String^ model1,String^ rocznik1,String^ cena1)
{
this->model=model1;
this->rocznik=rocznik1;
this->cena=cena1;
};
void Car::edytuj(String^ model1,String^ rocznik1,String^ cena1)
{
this->model=model1;
this->rocznik=rocznik1;
this->cena=cena1;
};
Declaration of class where method mentioned in error is:
public ref class Bazadanych
{
public:
cliext::list<Car^> Bazatorent;
cliext::list<Rented^> Bazarented;
cliext::list<Unavaible^> Bazaunavaible;
cliext::list<Car^>::iterator it1;
cliext::list<Rented^>::iterator it2;
cliext::list<Unavaible^>::iterator it3;
Bazadanych()
{
it1=Bazatorent.begin();
it2=Bazarented.begin();
it3=Bazaunavaible.begin();
};
bool Empty();
void Dodaj1(Car);
void Dodaj2(Rented);
void Dodaj3(Unavaible);
void Usun1(Car);
void Usun2(Rented);
void Usun3(Unavaible);
void Czysc();
};
and definition:
void Bazadanych::Dodaj1(Car Element)
{
this->Bazatorent.push_back(Element);
};
I have definitions and declarations in separatly .h and .cpp files. For other methods "Dodaj" and "Usun" I have exactly the same problems. If it could help the class Car is base class for class Rented and Unavaible.
I am pretty new in C++/CLI, so I will be very grateful if someone could help me.
I find the error message strange given that it's a managed class. But you can solve it by changing the method's signature to:
void Bazadanych::Dodaj1(Car^ Element) // notice the "^"
Same for the other similar methods.
I'm guessing that without the hat (^), the compiler treats the variable as a regular C++ class, and therefore requires a copy constructor for it, even though managed classes don't even have copy constructors (you can write them but they're never called implicitly like for regular C++ classes).
EDIT: About the error in your comment: Instead of instantiating the class like this:
Car car;
Do it like this:
Car^ car = gcnew Car();
It says what it means: you have no copy constructor for Car. It might look like this:
Car::Car(const Car& c) {
/* your code here*/
};
Some background here and here.

Resources