www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What is the wrong with my C++ interfacing

reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
The original C++ class
https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/types.hpp#L315:
template<typename _Tp> class Size_
{
public:
     typedef _Tp value_type;

     //! default constructor
     Size_();
     Size_(_Tp _width, _Tp _height);
     Size_(const Size_& sz);
     Size_(Size_&& sz) CV_NOEXCEPT;
     Size_(const Point_<_Tp>& pt);

     Size_& operator = (const Size_& sz);
     Size_& operator = (Size_&& sz) CV_NOEXCEPT;
     //! the area (width*height)
     _Tp area() const;
     //! aspect ratio (width/height)
     double aspectRatio() const;
     //! true if empty
     bool empty() const;

     //! conversion of another data type.
     template<typename _Tp2> operator Size_<_Tp2>() const;

     _Tp width; //!< the width
     _Tp height; //!< the height
};

// my auxiliary cpp code:
cv::Size_<int>* createSizeIntWH(int _width, int _height){
     return new cv::Size_<int>(_width, _height);
}

void deleteSizeInt(cv::Size_<int> *&sz){
     delete sz;
}

// d code:
extern(C++, cv){
class Size_(_Tp){
      disable this();

     final _Tp area() const;
     final double aspectRatio() const;
     final bool empty() const;

     _Tp width; //!< the width
     _Tp height; //!< the height
}
}

// my test code that fails:
Size_!int sz = createSizeIntWH(200, 100);
writeln(sz.width);

One of the problems is that sz.width is not printed as 200, but a 
random int.
Other problem is that if I try to call one of area, aspectRatio, 
and empty, it does not compile yielding a linker error:
error LNK2019: unresolved external symbol "public: int __cdecl 
cv::Size_<int>::area(void)const " (?area ?$Size_ H cv  QEBAHXZ) 
referenced in function _Dmain
Somehow linker cannot locate that symbol. Is this a name mangling 
issue?
In the same library I could successfully interface cv::Mat which 
is a template-free definition. I suspect if D allows interfacing 
C++ class templates since docs do not cover this, but only struct 
templates?
Mar 15 2020
parent reply drug <drug2004 bk.ru> writes:
15.03.2020 22:39, Ferhat Kurtulmuş пишет:
 
 The original C++ class
 https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/
ore/types.hpp#L315: 
 
 template<typename _Tp> class Size_
 {
 public:
      typedef _Tp value_type;
 
      //! default constructor
      Size_();
      Size_(_Tp _width, _Tp _height);
      Size_(const Size_& sz);
      Size_(Size_&& sz) CV_NOEXCEPT;
      Size_(const Point_<_Tp>& pt);
 
      Size_& operator = (const Size_& sz);
      Size_& operator = (Size_&& sz) CV_NOEXCEPT;
      //! the area (width*height)
      _Tp area() const;
      //! aspect ratio (width/height)
      double aspectRatio() const;
      //! true if empty
      bool empty() const;
 
      //! conversion of another data type.
      template<typename _Tp2> operator Size_<_Tp2>() const;
 
      _Tp width; //!< the width
      _Tp height; //!< the height
 };
 
 // my auxiliary cpp code:
 cv::Size_<int>* createSizeIntWH(int _width, int _height){
      return new cv::Size_<int>(_width, _height);
 }
 
 void deleteSizeInt(cv::Size_<int> *&sz){
      delete sz;
 }
 
 // d code:
 extern(C++, cv){
 class Size_(_Tp){
       disable this();
 
      final _Tp area() const;
      final double aspectRatio() const;
      final bool empty() const;
 
      _Tp width; //!< the width
      _Tp height; //!< the height
 }
 }
 
 // my test code that fails:
 Size_!int sz = createSizeIntWH(200, 100);
 writeln(sz.width);
What is the D version of `createSizeIntWH`? In C++ it returns a pointer but in D version it returns an instance.
 
 One of the problems is that sz.width is not printed as 200, but a random 
 int.
 Other problem is that if I try to call one of area, aspectRatio, and 
 empty, it does not compile yielding a linker error:
 error LNK2019: unresolved external symbol "public: int __cdecl 
 cv::Size_<int>::area(void)const " (?area ?$Size_ H cv  QEBAHXZ) 
 referenced in function _Dmain
 Somehow linker cannot locate that symbol. Is this a name mangling issue?
 In the same library I could successfully interface cv::Mat which is a 
 template-free definition. I suspect if D allows interfacing C++ class 
 templates since docs do not cover this, but only struct templates?
 
Mar 15 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Sunday, 15 March 2020 at 20:21:57 UTC, drug wrote:
 15.03.2020 22:39, Ferhat Kurtulmuş пишет:
 
 What is the D version of `createSizeIntWH`? In C++ it returns a 
 pointer but in D version it returns an instance.
extern(C++){ cv.Size_!int createSizeInt(); cv.Size_!int createSizeIntWH(int w, int h); void deleteSizeInt(ref cv.Size_!int sz); }
Mar 15 2020
parent reply drug <drug2004 bk.ru> writes:
15.03.2020 23:25, Ferhat Kurtulmuş пишет:
 On Sunday, 15 March 2020 at 20:21:57 UTC, drug wrote:
 15.03.2020 22:39, Ferhat Kurtulmuş пишет:

 What is the D version of `createSizeIntWH`? In C++ it returns a 
 pointer but in D version it returns an instance.
extern(C++){     cv.Size_!int createSizeInt();     cv.Size_!int createSizeIntWH(int w, int h);     void deleteSizeInt(ref cv.Size_!int sz); }
createSizeIntWH returns a pointer to instance, not an instance. Try: cv.Size_!int* createSizeIntWH(int w, int h);
Mar 15 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Sunday, 15 March 2020 at 20:46:14 UTC, drug wrote:
 15.03.2020 23:25, Ferhat Kurtulmuş пишет:
 On Sunday, 15 March 2020 at 20:21:57 UTC, drug wrote:
 15.03.2020 22:39, Ferhat Kurtulmuş пишет:

 What is the D version of `createSizeIntWH`? In C++ it returns 
 a pointer but in D version it returns an instance.
extern(C++){     cv.Size_!int createSizeInt();     cv.Size_!int createSizeIntWH(int w, int h);     void deleteSizeInt(ref cv.Size_!int sz); }
createSizeIntWH returns a pointer to instance, not an instance. Try: cv.Size_!int* createSizeIntWH(int w, int h);
I doubt it because in https://dlang.org/spec/cpp_interface.html#using_cpp_classes_from_d cpp code: Derived *createInstance(int i) d code: extern (C++){ ... Derived createInstance(int i); }
Mar 15 2020
next sibling parent drug <drug2004 bk.ru> writes:
15.03.2020 23:53, Ferhat Kurtulmuş пишет:
 
 I doubt it because in 
 https://dlang.org/spec/cpp_interface.html#using_cpp_classes_from_d
 
 cpp code:
 Derived *createInstance(int i)
 
 d code:
 extern (C++){
      ...
      Derived createInstance(int i);
 }
 
 
Ah, really, you use classes on D side.
Mar 15 2020
prev sibling parent reply Arine <arine123445128843 gmail.com> writes:
On Sunday, 15 March 2020 at 20:53:49 UTC, Ferhat Kurtulmuş wrote:
 On Sunday, 15 March 2020 at 20:46:14 UTC, drug wrote:
 15.03.2020 23:25, Ferhat Kurtulmuş пишет:
 On Sunday, 15 March 2020 at 20:21:57 UTC, drug wrote:
 15.03.2020 22:39, Ferhat Kurtulmuş пишет:

 What is the D version of `createSizeIntWH`? In C++ it 
 returns a pointer but in D version it returns an instance.
extern(C++){     cv.Size_!int createSizeInt();     cv.Size_!int createSizeIntWH(int w, int h);     void deleteSizeInt(ref cv.Size_!int sz); }
createSizeIntWH returns a pointer to instance, not an instance. Try: cv.Size_!int* createSizeIntWH(int w, int h);
I doubt it because in https://dlang.org/spec/cpp_interface.html#using_cpp_classes_from_d cpp code: Derived *createInstance(int i) d code: extern (C++){ ... Derived createInstance(int i); }
I wouldn't use a class on the D side, unless your C++ type uses virtual functions. Classes in D are different from structs, it is not the same as C++ where they are basically the same thing.
Mar 15 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Sunday, 15 March 2020 at 21:16:43 UTC, Arine wrote:
 On Sunday, 15 March 2020 at 20:53:49 UTC, Ferhat Kurtulmuş
 I wouldn't use a class on the D side, unless your C++ type uses 
 virtual functions. Classes in D are different from structs, it 
 is not the same as C++ where they are basically the same thing.
I know their differences, classes are reference types and structs are value types in D. I actually don't need this code. I've already wrapped many c code, but have no so much experience with interfacing C++ code. I am trying to understand capabilities of D in interfacing with C++ and its limits. I would like to know why I can interface a template-free class, but not a class template.
Mar 15 2020
parent reply Arine <arine123445128843 gmail.com> writes:
On Sunday, 15 March 2020 at 21:27:32 UTC, Ferhat Kurtulmuş wrote:
 On Sunday, 15 March 2020 at 21:16:43 UTC, Arine wrote:
 On Sunday, 15 March 2020 at 20:53:49 UTC, Ferhat Kurtulmuş
 I wouldn't use a class on the D side, unless your C++ type 
 uses virtual functions. Classes in D are different from 
 structs, it is not the same as C++ where they are basically 
 the same thing.
I know their differences, classes are reference types and structs are value types in D.
That's not the only difference. It's why your code doesn't work.
 I actually don't need this code. I've already wrapped many c 
 code, but have no so much experience with interfacing C++ code. 
 I am trying to understand capabilities of D in interfacing with 
 C++ and its limits. I would like to know why I can interface a 
 template-free class, but not a class template.
You can, you just aren't representing the C++ code properly in D. You don't want class, it means something different in D than in C++. This works for me, as it is using struct that corresponds to the C++ type. You have to use extern(C++, class), as it is using "class" on the C++ side, which produces a different mangling. extern(C++, cv){ extern(C++, class) struct Size_(_Tp){ disable this(); ~this() { } final _Tp area() const; final double aspectRatio() const; final bool empty() const; _Tp width; //!< the width _Tp height; //!< the height } } extern(C++){ cv.Size_!int* createSizeIntWH(int w, int h); } void main() { Size_!int* sz = createSizeIntWH(200, 100); writeln(sz.width); }
Mar 15 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Sunday, 15 March 2020 at 22:25:27 UTC, Arine wrote:
 On Sunday, 15 March 2020 at 21:27:32 UTC, Ferhat Kurtulmuş
 extern(C++, cv){
 extern(C++, class) struct Size_(_Tp){
      disable this();
 	~this() { }

     final _Tp area() const;
     final double aspectRatio() const;
     final bool empty() const;

     _Tp width; //!< the width
     _Tp height; //!< the height
 }
 }

 extern(C++){
     cv.Size_!int* createSizeIntWH(int w, int h);
 }

 void main()
 {
 	Size_!int* sz = createSizeIntWH(200, 100);
 	writeln(sz.width);
 }
This worked for me too. But member functions are still causing linker error. It seems like docs (https://dlang.org/spec/cpp_interface.html) do not cover those situations. Is there any other sources to read for it. Maybe you make a pull request to docs covering C++ interfacing tips in detail.
Mar 16 2020
parent reply drug <drug2004 bk.ru> writes:
On 3/16/20 10:11 AM, Ferhat Kurtulmuş wrote:
 On Sunday, 15 March 2020 at 22:25:27 UTC, Arine wrote:
 On Sunday, 15 March 2020 at 21:27:32 UTC, Ferhat Kurtulmuş
 extern(C++, cv){
 extern(C++, class) struct Size_(_Tp){
      disable this();
     ~this() { }

     final _Tp area() const;
     final double aspectRatio() const;
     final bool empty() const;

     _Tp width; //!< the width
     _Tp height; //!< the height
 }
 }

 extern(C++){
     cv.Size_!int* createSizeIntWH(int w, int h);
 }

 void main()
 {
     Size_!int* sz = createSizeIntWH(200, 100);
     writeln(sz.width);
 }
This worked for me too. But member functions are still causing linker error. It seems like docs (https://dlang.org/spec/cpp_interface.html) do not cover those situations. Is there any other sources to read for it. Maybe you make a pull request to docs covering C++ interfacing tips in detail.
Not tested: extern(C++, class) struct Size_(_Tp){ disable this(); ~this() { } extern(C++): // <- IIRC linkage should be set for members separately from aggregate final _Tp area() const; final double aspectRatio() const; final bool empty() const; _Tp width; //!< the width _Tp height; //!< the height }
Mar 16 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Monday, 16 March 2020 at 07:46:00 UTC, drug wrote:
 On 3/16/20 10:11 AM, Ferhat Kurtulmuş wrote:
 On Sunday, 15 March 2020 at 22:25:27 UTC, Arine wrote:
 On Sunday, 15 March 2020 at 21:27:32 UTC, Ferhat Kurtulmuş
 extern(C++, cv){
 extern(C++, class) struct Size_(_Tp){
      disable this();
     ~this() { }

     final _Tp area() const;
     final double aspectRatio() const;
     final bool empty() const;

     _Tp width; //!< the width
     _Tp height; //!< the height
 }
 }

 extern(C++){
     cv.Size_!int* createSizeIntWH(int w, int h);
 }

 void main()
 {
     Size_!int* sz = createSizeIntWH(200, 100);
     writeln(sz.width);
 }
This worked for me too. But member functions are still causing linker error. It seems like docs (https://dlang.org/spec/cpp_interface.html) do not cover those situations. Is there any other sources to read for it. Maybe you make a pull request to docs covering C++ interfacing tips in detail.
Not tested: extern(C++, class) struct Size_(_Tp){ disable this(); ~this() { } extern(C++): // <- IIRC linkage should be set for members separately from aggregate final _Tp area() const; final double aspectRatio() const; final bool empty() const; _Tp width; //!< the width _Tp height; //!< the height }
Ok, here is a solution. I opened my lib (yielded by my auxilary cpp) using 7zip. There are two files containing symbol names, 1.txt and 2.txt. I searched for names of member functions. They were not there because c++ compiler does not compile member functions of class templates because we don't actually use them. So, I simply include this line in my aux cpp file and recompiled it: template class cv::Size_<int>; I reopened 1.txt and they are there now: ?area ?$Size_ H cv QEBAHXZ ?aspectRatio ?$Size_ H cv QEBANXZ now everything works :D
Mar 16 2020
parent reply drug <drug2004 bk.ru> writes:
On 3/16/20 12:24 PM, Ferhat Kurtulmuş wrote:
 
 Ok, here is a solution. I opened my lib (yielded by my auxilary cpp) 
 using 7zip. There are two files containing symbol names, 1.txt and 
 2.txt. I searched for names of member functions. They were not there 
 because c++ compiler does not compile member functions of class 
 templates because we don't actually use them. So, I simply include this 
 line in my aux cpp file and recompiled it:
 
 template class cv::Size_<int>;
 
 I reopened 1.txt and they are there now:
 
 ?area ?$Size_ H cv  QEBAHXZ
 ?aspectRatio ?$Size_ H cv  QEBANXZ
 
 now everything works :D
 
Would be nice if you update wiki ;)
Mar 16 2020
parent Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Monday, 16 March 2020 at 09:28:15 UTC, drug wrote:
 On 3/16/20 12:24 PM, Ferhat Kurtulmuş wrote:
 
 Ok, here is a solution. I opened my lib (yielded by my 
 auxilary cpp) using 7zip. There are two files containing 
 symbol names, 1.txt and 2.txt. I searched for names of member 
 functions. They were not there because c++ compiler does not 
 compile member functions of class templates because we don't 
 actually use them. So, I simply include this line in my aux 
 cpp file and recompiled it:
 
 template class cv::Size_<int>;
 
 I reopened 1.txt and they are there now:
 
 ?area ?$Size_ H cv  QEBAHXZ
 ?aspectRatio ?$Size_ H cv  QEBANXZ
 
 now everything works :D
 
Would be nice if you update wiki ;)
It would be better for someone more experienced to do this ;)
Mar 16 2020