Why can't we use strings in C++ methods?

Dadoum dadoum at protonmail.com
Sat Nov 4 12:29:24 UTC 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:
>> On Saturday, 4 November 2023 at 11:18:02 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`
>>
>> So C-strings are just an array of characters that are governed 
>> by simple functions and D strings also defined the same.
>
> 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

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);
```


More information about the Digitalmars-d-learn mailing list