c++c++builder-xe8

Cannot Convert 'int' to 'const char *'


I'm working with c++ and XE8. Given the following code:

String __fastcall RemoveCharsFromString(String &str, const String &c)
{
    for(unsigned int i=0; i<c.Length(); ++i)
    {
        str.Delete(std::remove(str[0], str.LastChar(), c[i]), str.LastChar());
    }
}

Received errors:

Searching SO and the web, it's my understanding this error is usually received when code is written with single quotes when double quotes should have been used. I don't believe that scenario is applicable in this case.

The return type of String is Embarcadero's UnicodeString. Details can be found here: RAD Studio VCL Reference - UnicodeString Class


Solution

  • In C++Builder, String refers to System::String, which is an alias for System::UnicodeString in XE8.

    There are a lot of mistakes in your code.

    The System::String::Delete() method expects an index and a count as input, but that is not what you are trying to pass to it. You are expecting Delete() to work like the STL std::wstring::erase() method, and that is simply not the case.

    You are not taking into account that System::String::operator[] is 1-based. It is not 0-based, like your code is assuming.

    The System::String::LastChar() method returns a pointer to the last UTF-16 encoded Unicode character in the string. It does not return a pointer to the string's null terminator, like your code is assuming.

    You are calling the STL std::remove() algorithm that takes a range of iterators as input, shifts all copies of the specified value to the end of the range, and then returns a new iterator to where the "removed" values have been moved to within the range (so they can be erase()'d from the container that owns the iterators). You cannot mix System::String::Delete() and std::remove() the way you are attempting to do. If you really want to use std::replace(), you need to use it more like this instead:

    String __fastcall RemoveCharsFromString(String &str, const String &c)
    {
        for(int i = 1; i <= c.Length(); ++i)
        {
            const Char *start = str.c_str();
            const Char* end = start + str.Length();
            Char* ptr = std::replace(start, end, c[i]);
            str.Delete(1 + std::distance(start, ptr), std::distance(ptr, end));
        }
    }
    

    That being said, Embarcadero's RTL has its own System::Sysutils::StringReplace() function that you can use instead of std::replace():

    #include <System.SysUtils.hpp>
    
    String __fastcall RemoveCharsFromString(String &str, const String &c)
    {
        for(int i = 1; i <= c.Length(); ++i)
        {
            str = StringReplace(str, c[i], L"", TReplaceFlags() << rfReplaceAll);
        }
    }
    

    Or, if you need to take UTF-16 surrogates into account in the c string (which std::remove() does not account for):

    #include <System.SysUtils.hpp>
    #include <System.Character.hpp>
    
    String __fastcall RemoveCharsFromString(String &str, const String &c)
    {
        int i = 1; 
        while (i <= c.Length())
        {
            String chr;
            if (IsSurrogatePair(c, i))
                chr = c.SubString(i, 2);
            else
                chr = c.SubString(i, 1);
            str = StringReplace(str, chr, L"", TReplaceFlags() << rfReplaceAll);
            i += chr.Length(); 
        }
    }