I am trying to wrap a function which is used to cast to another type.
The C++ example is:
++
Handle(Geom_Point) aPnt1;
Handle(Geom_CartesianPoint) aPnt2, aPnt3;
aPnt2 = new Geom_CartesianPoint();
aPnt1 = aPnt2; // OK, standard assignment
aPnt3 = Handle(Geom_CartesianPoint)::DownCast (aPnt1);
// OK, the actual type of aPnt1 is Geom_CartesianPoint, although the static type of the handle is Geom_Point
where Geom_CartesianPoint inherits from Geom_Point. And Handle is some form of smart pointer. (Sorry, if the terminology is not correct, since I am not a pro).
In the header file, there are two functions defined as follows:
++
//! Down casting operator from handle to base type
template <class T2>
static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
DownCast (const handle<T2>& theObject)
{
return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
}
//! Down casting operator from pointer to base type
template <class T2>
static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
DownCast (const T2* thePtr)
{
return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));
}
What I tried something as the following in several forms:
proc downcast*[T; T2](this: Handle[T] ): Handle[T2] {.cdecl,
importcpp: "Handle('0)::Downcast(@)", header: "Standard_Handle.hxx".}
but when I compile I get:
Error: cannot instantiate: 'T2'
How can I fix this?
Well I think my lack of knowledge on OOP is quite deep.
I was just experimenting with this example, which fails. You cannot convert objects like that.
type
Person = object of RootObj
name: string
Student = object of Person
var a:Person
var b:Student
b.name = "joe"
a = b
The following works:
type
Person = ref object of RootObj
name: string
Student = ref object of Person
var a = new Person
var b = new Student
b.name = "joe"
a = b
b.name = "peter"
assert b.name == "peter"
assert a.name == "peter"
assert (a of Person)
assert (b of Student)
The first issue that I have above, is trying to mimic this behaviour in C++:
// Geom_CartesianPoint inherits from Geom_Point
Handle(Geom_Point) aPnt1;
Handle(Geom_CartesianPoint) aPnt2;
aPnt2 = new Geom_CartesianPoint();
aPnt1 = aPnt2; // OK, standard assignment
In my bindings, Geom_CartesianPoint inherits from Geom_Point. But their respective handles are unreleated.
In Nim:
import occt
var aPnt1: Handle[Geom_Point]
var aPnt2: Handle[Geom_CartesianPoint]
aPnt2 = newHandle( cnew newGeomCartesianPoint(1.0,2.0,3.0) )
#aPnt1 = aPnt2 # This fails
fails.
If I replace the last line with:
aPnt1 = cast[Handle[Geom_Point]](addr aPnt2) # This fails as well
it also fails:
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp: In function 'void NimMainModule()':
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp:117:92: error: use of deleted function 'NimMainModule()::<unnamed union>::<constructor>()'
117 | union { TY__34Wf6HfOat7G9bBA2jRAzyA* source; TY__7y8d4b9bdzRBHHJhUtf9af9ag dest; } LOC1;
| ^~~~
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp:117:15: note: 'NimMainModule()::<unnamed union>::<constructor>()' is implicitly deleted because the default definition would be ill-formed:
117 | union { TY__34Wf6HfOat7G9bBA2jRAzyA* source; TY__7y8d4b9bdzRBHHJhUtf9af9ag dest; } LOC1;
| ^
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp:117:84: error: union member 'NimMainModule()::<unnamed union>::dest' with non-trivial 'opencascade::handle<T>::handle() [with T = Geom_Point]'
117 | union { TY__34Wf6HfOat7G9bBA2jRAzyA* source; TY__7y8d4b9bdzRBHHJhUtf9af9ag dest; } LOC1;
| ^~~~
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp:117:92: error: use of deleted function 'NimMainModule()::<unnamed union>::~<constructor>()'
117 | union { TY__34Wf6HfOat7G9bBA2jRAzyA* source; TY__7y8d4b9bdzRBHHJhUtf9af9ag dest; } LOC1;
| ^~~~
/home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp:117:15: note: 'NimMainModule()::<unnamed union>::~<constructor>()' is implicitly deleted because the default definition would be ill-formed:
117 | union { TY__34Wf6HfOat7G9bBA2jRAzyA* source; TY__7y8d4b9bdzRBHHJhUtf9af9ag dest; } LOC1;
| ^
compilation terminated due to -fmax-errors=3.
Error: execution of an external compiler program 'g++ -c -std=gnu++14 -funsigned-char -w -fmax-errors=3 -fpermissive -I/usr/include/opencascade/ -I/home/jose/.choosenim/toolchains/nim-1.6.6/lib -I/home/jose/src/nimlang/occt.nim/examples -o /home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp.o /home/jose/.cache/nim/tmp01_d/@mtmp01.nim.cpp' failed with exit code: 1
How can I convert the references from one type to the other?
Finally a managed to do it with the following:
aPnt1 = newHandle( cast[ptr Geom_Point](aPnt2.get) )
where:
The downcasting can be done in a similar way.
So the following works for me:
import occt
# Geom_CartesianPoint a sub-class of Geom_Point;
var aPnt1: Handle[Geom_Point]
var aPnt2, aPnt3: Handle[Geom_CartesianPoint]
assert(`*`(aPnt2) of Geom_Point)
assert(`*`(aPnt2) of Geom_CartesianPoint)
aPnt2 = newHandle( cnew newGeomCartesianPoint(1.0,2.0,3.0) )
aPnt1 = newHandle( cast[ptr Geom_Point](aPnt2.get) )
assert (`*`(aPnt1).x) == (`*`(aPnt2).x)
aPnt3 = newHandle( cast[ptr Geom_CartesianPoint](aPnt1.get) )
assert (`*`(aPnt1).x) == (`*`(aPnt3).x)
I am not sure if there is any better way of doing so.
You can use
*x
instead of
`*`(x)
And ideally you use some other operator, unary * for pointer deref is not idiomatic.
Thanks Araq. I will try that this afternoon, but I think I tried and it failed for some reason. In any case, I will probably hide completely needing to do so.
I continue with the doubt about how to properly wrap:
template <class T2>
static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
DownCast (const handle<T2>& theObject)
{
return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
}
given that later is used like this:
aPnt3 = Handle(Geom_CartesianPoint)::DownCast (aPnt1);
and why the following is producing the cannot instantiate 'T2' error:
proc downcast*[T; T2](this: Handle[T] ): Handle[T2] {.cdecl, importcpp: "Handle('0)::Downcast(@)".}
Good point. In fact, this works:
aPnt3 = downcast[Geom_Point, Geom_CartesianPoint](aPnt1)
Is there a way to leave it like the following?
aPnt3 = downcast[Geom_CartesianPoint](aPnt1) # Given that aPnt1's type is Geom_Point
PS: *x worked for me. Thanks.
You don't have to give A if it can be inferred from an argument.
proc downcast*[B](this: Handle[auto] ): Handle[B] {...}
@sls1005 thanks a lot for that.
But for some reason is failing. I got:
...
proc dcast*[T](this: Handle[auto] ):Handle[T] {.cdecl, importcpp: "\'0::DownCast(@)".}
...
and
import occt
var aPnt1: Handle[Geom_Point]
var aPnt2, aPnt3: Handle[Geom_CartesianPoint]
aPnt2 = newHandle( cnew newGeomCartesianPoint(1.0,2.0,3.0) ) #
aPnt1 = newHandle( cast[ptr Geom_Point](aPnt2.get) )
#echo typeof(aPnt1) # --> Handle[geom_types.GeomPoint]
#echo typeof(aPnt3) # --> Handle[geom_types.GeomCartesianPoint]
aPnt3 = dcast[Geom_CartesianPoint]( aPnt1 )
The error I got is:
Error: type mismatch: got <void, Handle[geom_types.GeomPoint]>
but expected one of:
proc `()`(this: BitPredicate; theLink: BVH_EncodedLink): bool
first type mismatch at position: 1
required type for this: BitPredicate
but expression 'dcast[Geom_CartesianPoint]' is of type: void
....
Why am I getting <void, Handle[geom_types.GeomPoint]> instead of Handle[geom_types.GeomPoint]? Which it is what I get when I echo typeof(aPnt1).but expression 'dcast[Geom_CartesianPoint]' is of type: void
Maybe you forgot the parentheses?
I don't think so. It is complaining about line:
aPnt3 = dcast[Geom_CartesianPoint]( aPnt1 )
But this compiles:
proc static_cast[T](self: auto): T {.importcpp: "static_cast<'0>(#)".}
var x: int64 = 1
echo static_cast[bool](x)
Maybe use auto or Handle (without brackets) instead of Handle[auto]?It continues failing:
# nim cpp -r tmp01
import occt
proc mydowncast*[A; B](this: Handle[A] ): Handle[B] {.cdecl, importcpp: "\'0::DownCast(@)".}
proc dcast1*[T](this: auto ):T {.cdecl, importcpp: "\'0::DownCast(@)".}
proc dcast2*[T](this: Handle[auto] ): Handle[T] {.cdecl, importcpp: "\'0::DownCast(@)".}
proc dcast3*[T](this: Handle ): Handle[T] {.cdecl, importcpp: "\'0::DownCast(@)".}
var aPnt1: Handle[Geom_Point]
var aPnt2, aPnt3: Handle[Geom_CartesianPoint]
aPnt2 = newHandle( cnew newGeomCartesianPoint(1.0,2.0,3.0) ) #
aPnt1 = newHandle( cast[ptr Geom_Point](aPnt2.get) )
#aPnt3 = mydowncast[Geom_Point,Geom_CartesianPoint](aPnt1) # <-- This works
#aPnt3 = dcast1[Handle[Geom_CartesianPoint]](aPnt1) # <-- This doesn't
#aPnt3 = dcast2[Geom_CartesianPoint](aPnt1) # <-- This doesn't
#aPnt3 = dcast3[Geom_CartesianPoint](aPnt1) # <-- This doesn't
One thing that puzzles me is the error report:
Error: type mismatch: got <void, Handle[geom_types.GeomPoint]>
but expected one of:
proc `()`(this: BitPredicate; theLink: BVH_EncodedLink): bool
first type mismatch at position: 1
required type for this: BitPredicate
but expression 'dcast3[Geom_CartesianPoint]' is of type: void
proc `()`(this: BlendFuncTensor; row: cint; col: cint; mat: cint): cfloat
first type mismatch at position: 1
required type for this: BlendFuncTensor
but expression 'dcast3[Geom_CartesianPoint]' is of type: void
proc `()`(this: ChFiDS_Map; i: cint): TopToolsListOfShape
first type mismatch at position: 1
required type for this: ChFiDS_Map
but expression 'dcast3[Geom_CartesianPoint]' is of type: void
....
We can see that is complaining about ` 'dcast3[Geom_CartesianPoint]' is of type: void`. But it is trying to much the call against the operator (). I am using that experimental feature in some places across the library:
{.experimental: "callOperator".}
Could it be a bug in Nim?