Jump to content
Henrick Wibell Hellström

Delphi method overload compatibility with C++ Win64 Modern

Recommended Posts

I apologize if this question has been posted before, but as far as I can tell, this should be a relatively new compatibility issue. It concerns using Delphi components in a RAD Studio 12 C++ Win64 Modern project. I am interested in known workarounds.

For as long as I remember, it has been possible to write code like this:
 

type
  ObjectIdentifier = type AnsiString;

  TFoo = class
    procedure Bar(const Value: AnsiString); overload;
    procedure Bar(const Value: ObjectIdentifier); overload;
  end;

By using the keyword "type" in the declaration of ObjectIdentifier, it becomes a new type, and not just another name for the same type. Furthermore, it only matters in parameter declarations, such as this. You are free to assign AnsiString values to variables and parameters of the declared type, and vice versa, except when it comes to method overloading and operator overloading.

The problem is that this seems to be broken in version 12 C++ Win64 Modern. If you output a hpp file corresponding to the above declarations, there will be a compiler error indicating that the Bar methods have identical parameters. Earlier C++ compilers have not had a problem with this.

Is anyone aware of an optimal work around?

Edited by Henrick Wibell Hellström
Grammar error

Share this post


Link to post
6 hours ago, Henrick Wibell Hellström said:

Earlier C++ compilers have not had a problem with this.

I don't have an older version installed right now to verify this with, but I would expect ALL compiler versions to have a problem with this.

 

Yes, the 'type' specifier in Delphi creates a new distinct type, which you can declare overloads with.  But in C++, AnsiString is just a typedef alias for AnsiStringT<0>, and your ObjectIdentifier is just a typedef alias for AnsiString, and thus is also an alias for AnsiStringT<0>.  And since typedef just creates aliases, not distinct types, they are both actually the same type, which you can't use to declare overloads with.

 

I'm sure this has come up before in past versions.

Edited by Remy Lebeau

Share this post


Link to post
5 hours ago, Remy Lebeau said:

Yes, the 'type' specifier in Delphi creates a new distinct type, which you can declare overloads with.  But in C++, AnsiString is just a typedef alias for AnsiStringT<0>, and your ObjectIdentifier is just a typedef alias for AnsiString, and thus is also an alias for AnsiStringT<0>.  And since typedef just creates aliases, not distinct types, they are both actually the same type, which you can't use to declare overloads with. 

Thank you for your insights. Do you have any good idea for a workaround? I suppose you can use {$NODEFINE TFoo} to leave the entire class out of the hpp file, or add a 'dummy' parameter at the end of either overloaded Bar method, but neither solutions strikes me as examples of good coding.

Share this post


Link to post
10 hours ago, Henrick Wibell Hellström said:

Thank you for your insights. Do you have any good idea for a workaround?

The only way to make your ObjectIdentifier be a unique type in C++ is to declare it as a class or struct, either with an AnsiString data member, or maybe even derived from AnsiString. You could declare Object Identifier as {$NODEFINE} on the Delphi side. But, you may or may not run into compatibility issues, so you should consider making ObjectIdentifier be a record on the Delphi side and then the compiler can general a compatible struct on the C++ side.

 

Share this post


Link to post

Indeed, yes, but it would cause ripple effects in the Delphi code, if ObjectIdentifier variables are passed to Format calls or Exception constructors. In Delphi, records with operator overloads can't be passed as elements of variant array arguments. Not even if they implement a suitable Implicit operator. Changing the declaration from 'type AnsiString' to a record, would also entail a complete rewrite of any constant declaration in the following form:

const  
  cAttrValueIdentifiers: array [0..1] of ObjectIdentifier = (
    '2.5.4.41', // id-at-name
    '2.5.4.4' // id-at-surname
  );

to:

const  
  cAttrValueIdentifiers: array [0..1] of ObjectIdentifier = (
    (fData: '2.5.4.41'), // id-at-name
    (fData: '2.5.4.4') // id-at-surname
  );

If there are several hundreds such constants, and it is critical that each is correct, it is not something you could entrust a Delphi IDE recordable macro. Granted, you could change the type of the constants to array [] of AnsiString, but that would entail a lack of clarity.
 

Edited by Henrick Wibell Hellström

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×