0
votes

Extension of C++ constructor in Borland C++Builder.

I have some code that concatenates UnicodeString values (previously AnsiString).

UnicodeString string="test1";
Variant v1="test";
string = string + UnicodeString(v1);

[bcc32 Error] myTest.cpp(154): E2015 Ambiguity between 'System::UnicodeString::UnicodeString(const System::UnicodeString &) at c:\program files (x86)\embarcadero\studio\17.0\include\windows\rtl\ustring.h:86' and 'System::UnicodeString::UnicodeString(const wchar_t *) at c:\program files (x86)\embarcadero\studio\17.0\include\windows\rtl\ustring.h:89'

Now, the problem is that Variant is ambiguous and the compiler complains about this ambiguity (fair enough).

If I add direct cast to string, it works ok.

string = string + UnicodeString(v1.As<UnicodeString>());

The problem is that my code is huge and there are thousands of such pieces. I would like to introduce a new explicit typedef or macro that does this :

Given argument v1 is Variant, it performs instead of this:

UnicodeString(v1)

It performs this instead:

UnicodeString(v1.As<UnicodeString>())

I understand this could be achieved by extending somehow (not sure how) constructor or typedef of UnicodeString by adding UnicodeString(Variant) (or macro ?).

PS. UnicodeString is a system class, so I can not modify it directly.

PS1. Same problem (even more code pieces) is with AnsiString. Making a function does not work :( . For AnsiString it does not work :(.

Definition of AnsiString in system header (sysmac.h) :

typedef AnsiStringT<0> AnsiString;

Example:

AnsiString myTest::AnsiString(Variant v)
{
    return "";
}

[bcc32 Error] .cpp(122): E2235 Member function must be called or its address taken

2
just define a functionCheers and hth. - Alf
For AnsiString it does not work :(. definition in system header (sysmac.h) : typedef AnsiStringT<0> AnsiString; example: AnsiString myTest::AnsiString(Variant v) { return ""; } [bcc32 Error] .cpp(122): E2235 Member function must be called or its address takenAbc1234
Don't name your function AnsiString(), name it something like AsAnsiString() instead. And there is no point in making it a member of your class (unless you define it as static) since it is not accessing any members of that class. And why return "" instead of return v.As<AnsiString>()?Remy Lebeau

2 Answers

0
votes

I think what you are trying to do would severely harm readability of your code. Changing the constructor of a built-in class (even if it was possible) would certainly be surprising to anyone reading your code. A better solution would be to just add a function somewhere

void addVariantToUnicodeString(UnicodeString& string, Variant& v){
    string = string + UnicodeString(v1.As<UnicodeString>());
}

Or something like that (possibly using templates). Now just replace your code correspondingly. As an additional benefit, your code will now state clearly what it is doing instead of simply performing obscure string operations. Of course, you can also construct your own string management class providing the functionality that you need. This slightly depends on the complexity and extent of your problem.

0
votes

PS. UnicodeString is a system class, so I can not modify it directly.

In C++Builder, UnicodeString and AnsiString/AnsiStringT are just classes like any other (though you cannot derive custom descendants from them, as they are marked as __declspec(delphireturn) to prevent that). UnicodeString is declared in ustring.h, AnsiStringT is declared in dstring.h, and AnsiString is declared in sysmac.h (as you already pointed out). You could simply edit ustring.h and dstring.h to add custom constructors to those classes, for example:

ustring.h

namespace System
{
  ...
  class RTL_DELPHIRETURN UnicodeString
  {
  ...
  public:
    ...
    explicit __fastcall UnicodeString(const Variant &src) : Data(0) { *this = src.As<UnicodeString>(); }
    ...
  };
  ...
}

dstring.h

namespace System
{
  ...
  template <unsigned short CP>
  class RTL_DELPHIRETURN AnsiStringT : public AnsiStringBase
  {
  ...
  public:
    ...
    explicit __fastcall AnsiStringT(const Variant &src) : AnsiStringBase() { *this = src.As< AnsiString<T> >();}
  };
  ...
}

The alternative would be to define a custom operator+() in your own code to concatenate a Variant to a UnicodeString:

UnicodeString operator+(const UnicodeString& s, const Variant& v)
{
    return s + v.As<UnicodeString>();
} 

But that would require changing statements like this:

string = string + UnicodeString(v1);

To this instead:

string = string + v1;

And if you were going to go to the trouble of making that change, then you could just forget everything above and do this instead (like you should have been doing in the first place):

string = string + v1.As<UnicodeString>();