digitalmars.D.learn - Why can't we use strings in C++ methods?
- Dadoum (5/5) Nov 03 2023 I was wondering why C++ linkage forbids strings as arguments
- Imperatorn (2/7) Nov 04 2023 Can you provide an example of exactly what you want to do?
- Dadoum (22/30) Nov 04 2023 ```d
- Emmanuel Danso Nyarko (7/38) Nov 04 2023 So C-strings are just an array of characters that are governed by
- Johan (14/45) Nov 04 2023 This is not true. D string (=slice) variables store the length of
- Dadoum (75/122) Nov 04 2023 What I don't understand is why it cannot use the template it
- Emmanuel Danso Nyarko (10/57) Nov 04 2023 You're right but that's not what he's looking for I think. He
- Dadoum (7/14) Nov 04 2023 I don't think the strings are being translated in any way when we
- Emmanuel Danso Nyarko (8/24) Nov 04 2023 There is a syntax disagreement here that's why the D compiler is
- Dadoum (17/25) Nov 04 2023 I don't think it's related to the existence of std::string at all
- Emmanuel Danso Nyarko (7/33) Nov 04 2023 Here too you will get the same error, cannot be mapped to C++.
- Basile B. (12/38) Nov 04 2023 The type simply cannot be mangled using the C++ mangler as it
- Imperatorn (2/15) Nov 04 2023 Could the mangling be provided with pragma and made to work?
- Dadoum (4/7) Nov 04 2023 So with few patches could we make it work? DMD can write the C++
- Imperatorn (6/37) Nov 04 2023 We can just assume what you're doing on the C++-side. Are you
- Dadoum (5/11) Nov 04 2023 I will use whatever D gives me in the C++ header, because in fact
- Paul Backus (30/35) Nov 04 2023 `extern(C++)` functions use C++ name mangling, which includes the
- Dadoum (27/36) Nov 04 2023 I use another workaround myself:
- Emmanuel Danso Nyarko (2/11) Nov 04 2023 Simply add perfectly explained!
I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.
Nov 03 2023
On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.Can you provide an example of exactly what you want to do?
Nov 04 2023
On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote:On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.Can you provide an example of exactly what you want to do?
Nov 04 2023
On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote:On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote:So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation.On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.Can you provide an example of exactly what you want to do?
Nov 04 2023
On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote:On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote:This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same.
Nov 04 2023
On Saturday, 4 November 2023 at 12:21:45 UTC, Johan wrote:On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote:What I don't understand is why it cannot use the template it defines in the header. Here it is: ```c++ // Automatically generated by LDC Compiler #pragma once #include <assert.h> #include <math.h> #include <stddef.h> #include <stdint.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE #else /// Represents a D [] array template<typename T> struct _d_dynamicArray final { size_t length; T *ptr; _d_dynamicArray() : length(0), ptr(NULL) { } _d_dynamicArray(size_t length_in, T *ptr_in) : length(length_in), ptr(ptr_in) { } T& operator[](const size_t idx) { assert(idx < length); return ptr[idx]; } const T& operator[](const size_t idx) const { assert(idx < length); return ptr[idx]; } }; #endif extern "C" void hello(_d_dynamicArray< const char > arg); ``` And the D compiler can generate templates in the mangled name, as this D code is translated to C++: ```d class Foo(T) {} extern (C++) void hello2(Foo!char arg2) { } ``` ```c++ // Automatically generated by LDC Compiler #pragma once #include <assert.h> #include <math.h> #include <stddef.h> #include <stdint.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE #else /// Represents a D [] array template<typename T> struct _d_dynamicArray final { size_t length; T *ptr; _d_dynamicArray() : length(0), ptr(NULL) { } _d_dynamicArray(size_t length_in, T *ptr_in) : length(length_in), ptr(ptr_in) { } T& operator[](const size_t idx) { assert(idx < length); return ptr[idx]; } const T& operator[](const size_t idx) const { assert(idx < length); return ptr[idx]; } }; #endif template <typename T> class Foo; extern void hello2(Foo<char >* arg2); ```On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote:This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same.
Nov 04 2023
On Saturday, 4 November 2023 at 12:21:45 UTC, Johan wrote:On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote:You're right but that's not what he's looking for I think. He wants to understand why it doesn't compile at all. One major cause of failed compilation is syntax disagreements And my main point is that because C++ doesn't know independent 'string' and that the string in C++ is a standard template library, the D compiler decides to stop any symbol generated interaction with string because C++ syntatically doesn't know 'string'. Maybe the compiler team could provide a better answer to him but that's what I think.On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote:This is not true. D string (=slice) variables store the length of the string in addition to the reference to the array of characters. The reason this "works" with `extern (C)` is because the C mangling of a function name does not include the type of the parameters. Note that C does not have a `string` type, so to call the function from C you will have to write a different function signature in C (you'll see that `char[]` will not work). It does not work with `extern(C++)` because the C++ mangling of a function _does_ include the type of the parameters, and there is no built-in C++ type that is equivalent to D's `string`. -Johan```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same.
Nov 04 2023
On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote:[...] So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation.I don't think the strings are being translated in any way when we change the linkage. Strings in D are dynamic arrays of chars, the C binding code is giving us a template representing D's dynamic arrays, and so I thought that we could also use it in C++ for interoperability with D dynamic arrays.
Nov 04 2023
On Saturday, 4 November 2023 at 12:34:28 UTC, Dadoum wrote:On Saturday, 4 November 2023 at 12:01:11 UTC, Emmanuel Danso Nyarko wrote:There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string'[...] So C-strings are just an array of characters that are governed by simple functions and D strings also defined the same. So you could see that D strings are possibly built on the architecture of C strings. In C++, string is a complex standard template library that generates complex symbols and cannot be mapped as it is based on a standard library implementation.I don't think the strings are being translated in any way when we change the linkage. Strings in D are dynamic arrays of chars, the C binding code is giving us a template representing D's dynamic arrays, and so I thought that we could also use it in C++ for interoperability with D dynamic arrays.
Nov 04 2023
On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote:[...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string'I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ```
Nov 04 2023
On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote:On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote:Here too you will get the same error, cannot be mapped to C++. C++ mangles dynamic arrays as pointer arrays(uses the 'P' symbol), which is supported by D for interfacing with C. Another disagreement here using it in c++ interop. Hence will not compile. Once again, I think the compiler team will be the best to give you what you're looking for.[...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string'I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ```
Nov 04 2023
On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote:On Saturday, 4 November 2023 at 13:45:56 UTC, Emmanuel Danso Nyarko wrote:The type simply cannot be mangled using the C++ mangler as it does not exist over there. You might have the impression that this should be allowed, e.g as an extension, but keep in mind that `extern(C++)` is firstly designed to link against object produced by a C++ compiler. Now why this works in `extern(C)` ? Because C does not mangle the parameters, a function linkage name is simply its unqualified name, so linking will work even if the parameter types are specific to D. Now there is still the question whether the `extern(C)` code will work as expected or not.[...] There is a syntax disagreement here that's why the D compiler is instantly stopping you from doing any symbol generated interaction with string in C++ interop. C++ doesn't know 'string' and C++ mangles with parameters and so passing string will make string get involved with the symbol generation and since string(std::string) in C++ is a template library, the D compiler stops you from engaging with 'string'I don't think it's related to the existence of std::string at all since all dynamic array types are forbidden. ```d extern (C++) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ``` also fails to compile while this works: ```d extern (C) void hello(ubyte[] arg) { import std.stdio; writeln(arg); } ```
Nov 04 2023
On Saturday, 4 November 2023 at 14:33:56 UTC, Basile B. wrote:On Saturday, 4 November 2023 at 13:51:20 UTC, Dadoum wrote:Could the mangling be provided with pragma and made to work?[...]The type simply cannot be mangled using the C++ mangler as it does not exist over there. You might have the impression that this should be allowed, e.g as an extension, but keep in mind that `extern(C++)` is firstly designed to link against object produced by a C++ compiler. Now why this works in `extern(C)` ? Because C does not mangle the parameters, a function linkage name is simply its unqualified name, so linking will work even if the parameter types are specific to D. Now there is still the question whether the `extern(C)` code will work as expected or not.
Nov 04 2023
On Saturday, 4 November 2023 at 14:33:56 UTC, Basile B. wrote:[...] Now there is still the question whether the `extern(C)` code will work as expected or not.So with few patches could we make it work? DMD can write the C++ function prototype (as it does it with `extern (C)`) and then mangle it as the template it uses in C?
Nov 04 2023
On Saturday, 4 November 2023 at 11:18:02 UTC, Dadoum wrote:On Saturday, 4 November 2023 at 10:08:20 UTC, Imperatorn wrote:We can just assume what you're doing on the C++-side. Are you using std::string? You could try as a pointer + length and it might work, but without seeing your complete code it's quite hard to know what you want to do.On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:```d extern (C) void hello(string arg) { import std.stdio; writeln(arg); } ``` Compiles fine with dmd, ldc2 and gdc. ```d extern (C++) void hello(string arg) { import std.stdio; writeln(arg); } ``` Doesn't compile. DMD: `Internal Compiler Error: type `string` cannot be mapped to C++` GDC and LDC2: `function 'example.hello' cannot have parameter of type 'string' because its linkage is 'extern(C++)'` And I am wondering why the type can be mapped to a template in C but not in C++. (you can see the template used when you compile with `-H --HCf=./header.h`I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.Can you provide an example of exactly what you want to do?
Nov 04 2023
On Saturday, 4 November 2023 at 12:07:12 UTC, Imperatorn wrote:[...] We can just assume what you're doing on the C++-side. Are you using std::string? You could try as a pointer + length and it might work, but without seeing your complete code it's quite hard to know what you want to do.I will use whatever D gives me in the C++ header, because in fact I am using Swift on the other side, so using std::string isn't useful. I already made a conversion function from Swift strings to D strings when they are represented with C linkage.
Nov 04 2023
On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:I was wondering why C++ linkage forbids strings as arguments while we can with the C one. With C linkage, it's translated to a template that's defined in the automatically generated header, but it just doesn't compile in C++.`extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. As a workaround, you can convert the slice to a `struct`: ```d struct DSlice(T) { T* ptr; size_t length; T[] opIndex() => ptr[0 .. length]; } DSlice!T toDslice(T)(T[] slice) { return DSlice!T(slice.ptr, slice.length); } extern(C++) void hello(DSlice!(const(char)) arg) { import std.stdio; writeln(arg[]); } void main() { const(char)[] greeting = "hello"; hello(greeting.toDslice); } ```
Nov 04 2023
On Saturday, 4 November 2023 at 14:21:49 UTC, Paul Backus wrote:[...] `extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. As a workaround, you can convert the slice to a `struct`: [...]I use another workaround myself: ```d extern (C++) struct List(T) { // or extern (C) T[] self; alias self this; } extern (C++) void hello(List!ubyte arg) { import std.stdio; writeln(arg); } ``` but it means adding a lot of edge cases to the mixins I use for bindings while showing that C++ can express D arrays. (translated to ```c++ template <typename T> struct List final { _d_dynamicArray< T > self; List() { } }; extern void hello(List<uint8_t > arg); ``` )
Nov 04 2023
On Saturday, 4 November 2023 at 14:21:49 UTC, Paul Backus wrote:On Saturday, 4 November 2023 at 03:00:49 UTC, Dadoum wrote:Simply add perfectly explained![...]`extern(C++)` functions use C++ name mangling, which includes the types of the parameters in the mangled name. However, since C++ does not have a built-in slice type like D's `T[]`, there is no valid C++ mangling for a D slice. Because of this, it is impossible to compile an `extern(C++)` function that has a D slice as a parameter. [...]
Nov 04 2023