Link to home
Start Free TrialLog in
Avatar of barzangy
barzangy

asked on

uppercase transformation

Why doesn't this code compile under Borland C++ builder 5.0?

#include <string>
#include <algorithm>
#include <cctype>
#include <locale>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
        string s = "abcd";
        transform(s.begin(), s.end(), s.begin(), toupper);
        cout << s << endl;
        cin.ignore();
        return 0;
}
Avatar of jkr
jkr
Flag of Germany image

There is no 'transform' that works like this:

transform
template<class InIt, class OutIt, class Unop>
    OutIt transform(InIt first, InIt last, OutIt x, Unop uop);
template<class InIt1, class InIt2, class OutIt, class Binop>
    OutIt transform(InIt1 first1, InIt1 last1, InIt2 first2,
        OutIt x, Binop bop);

So, you should use


       string s = "abcd";
       string out;
       transform(s.begin(), s.end(), out, toupper);

(just a guess, I never used it)
Avatar of barzangy
barzangy

ASKER

JKR: this code compiles under linux g++ linux and vc++ 6.0 and compaq cpp under vms. it just doesn't compile under borland c++. to make it compile I should declare a second function like this:

int mytoupper(int c) {
 return toupper(c);
}

transform(s.begin(), s.end(), s.begin(), mytoupper);

the transform algorithm needs a binary or unary operator. toupper is neither of those and hence gives an error when you try to compile it.
Ah, it might be a problem with the Borland compiler not defining the toupper class or the transform template correctly? Nietod did mention the other day that Borland's C++ compiler scored rather badly in compliance tests!
Exactly what do you get for an error.
There is nothing wrong with the code.
It compiles and works correctly in VC++ and in the GNU compiler.

toupper might be overloaded in Borland C++ builder 5.0
Do a test, and see if the following will compile:

wstring w = L"abcd";
transform(w.begin(), w.end(), w.begin(), towupper);

If the above code compiles, then you know you have a problem with toupper
Axter,
The following program compiles correctly. But what does this capital L letter before the "abcd" mean ?

Before I got the error message:

[C++ Error] Unit1.cpp(12): E2285 Could not find a match for 'transform<InputIterator1,InputIterator2,OutputIterator,BinaryOperation>(char *,char *,char *,charT (*)(charT,const locale &))'


#include <string>
#include <algorithm>
#include <cctype>
#include <locale>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
        wstring w = L"abcd";
        transform(w.begin(), w.end(), w.begin(), towupper);
        wcout << w << endl;
        cin.ignore();
        return 0;
}
FYI,
string s = "abcd";
string out;
transform(s.begin(), s.end(), out, toupper);

You wouldn't be able to compile this.
To compile it, you would have to change it to the following:

string s = "abcd";
string out;
transform(s.begin(), s.end(), out.begin(), toupper);

But this would be a problem too, because the std::transform function is going to try to put the data in the OUT variable, even though the OUT variable has not assigned space for the incoming data.

You could do the following:
string Src = "abcd";
string Dest;
Dest.reserve(Src.size()+1);//Add 1 for NULL terminator
transform(Src.begin(), Src.end()+1, Dest.begin(), toupper);

However, normally if you just want to make the same string upper case, you would have the source string and the destination string being one and the same.

transform(s.begin(), s.end(), s.begin(), toupper);
>>But what does this capital L letter before the "abcd"
>>mean
It makes it so that you can compile the string to a wide character target.
wstring is a wide character variable, so you need to initialize it with a wide character string.
>>The following program compiles correctly.

So if it compiles correctly with towupper, then you know you have a problem with the toupper() function.

This is not a template problem with the std::transform function.  If the Borland template std::transform function was ill formed, then you wouldn't have been able to compile it with the towupper() function.

VC++ has to versions of toupper.  One is _toupper() and the other is toupper().
The _toupper() function is the non-ANSI function.
Fortunetly in VC++ both the _toupper and the toupper functions take the same variable type, returns the same variable type, and functions the same.

I'm thinking that the Borland C++ compiler also has a non-ANSI C++ _toupper function.

Try the following test:
transform(s.begin(), s.end(), s.begin(), _toupper);
Is this L a c++ standard format or just a borland c++ builder extension? where is it documented?
>>Is this L a c++ standard format or just a borland c++
>>builder extension? where is it documented?
This is part of the C++ standard.
See Section 2.13.2 of the 1998 ANSI C++ Standards.
I found the following in ctype.h

#if !defined(__STDC__)     /* NON-ANSI */
#define _toupper(__c)   ((__c) + 'A' - 'a')
#define _tolower(__c)   ((__c) + 'a' - 'A')
#endif

but then I found also:
int     _RTLENTRY _EXPFUNC _ltoupper(int __ch);

and:

#if defined( __USELOCALES__ )
/* The following four functions cannot be macros, since the Rogue Wave headers
   #undef them.  So instead we'll use inline functions. */

/* Inline functions in "C" mode will disable precompiled headers if they are
   generated out-of-line.  Enabling debugging info, by default, will do this.
   Since most folks build with debug info frequently, we enable the -vi switch
   which forces these inline functions to be expanded inline even if debug
   info is enabled.
*/
#pragma option push -vi
__inline int     _RTLENTRY _EXPFUNC tolower(int __ch)      { return _ltolower(__ch);  }
__inline int     _RTLENTRY _EXPFUNC toupper(int __ch)      { return _ltoupper(__ch);  }
__inline _WINT_T _RTLENTRY _EXPFUNC towlower(_WINT_T __ch) { return _ltowlower(__ch); }
__inline _WINT_T _RTLENTRY _EXPFUNC towupper(_WINT_T __ch) { return _ltowupper(__ch); }
#pragma option pop /* -vi */

#define _wcsupr    _lwcsupr
#define _wcslwr    _lwcslwr

#endif  /*  __USELOCALES__  */

And:
using std::_ltoupper;



Using _ltoupper works just fine, like:

string w = "abcd";
transform(w.begin(), w.end(), w.begin(), _ltoupper);






FYI,
>>Using _ltoupper works just fine, like:
_ltoupper is not part of the ANSI C++ standards.
Niether is _toupper.

So your code may work, but it wouldn't be portable.
If you're not worried about portability, then this shouldn't be a problem.
You could also try the following:

#ifdef _toupper
#undef _toupper
#endif
transform(s.begin(), s.end(), s.begin(), toupper);
If my last posted code compiles, then that should be portable.
I was trying to write a program that copiles under linux and windows (with bcb 5.0) without #ifdef statements, it seems that I have to live with that. because _ltoupper is not defined in gnu c++ compiler. so it is a pitty but I guess I'll give Axter the points. Thanks all.

 
_toupper is not defined in bcb 5.0
>>under linux and windows (with bcb 5.0)

With the #ifdef I posted, that should be portable in to both linux and windows.
It should be able to compile to any compiler.
>>_toupper is not defined in bcb 5.0
What was the ctype.h file that you posted?
>>_toupper is not defined in bcb 5.0

So the #ifdef above has no effect.
It was from borland bcb 5.0, but because __STDC__ is defined at that moment. so the _toupper is not defined.
>>So the #ifdef above has no effect.
It looks like you're right, but could you give it a quick test anyway?

I have a hunch that it still might work.
Ok
I tried it just now, no it doesn't work.
>>I tried it just now, no it doesn't work.
Ok, I have one more idea.
Try it without using cctype include.

#include <string>
#include <algorithm>
#include <locale>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
       string s = "abcd";
       transform(s.begin(), s.end(), s.begin(), toupper);
       cout << s << endl;
       cin.ignore();
       return 0;
}
The best way was to define:
int mytoupper(int c) {
     return toupper(c);
}

and then using this in transform.

This will work on every platform! (optimistic enough)
>>Ok, I have one more idea.
>>Try it without using cctype include.


I tried that before. and again it doesn't work.
>>I tried that before. and again it doesn't work.

Oh well.  I'm out of ideas.
I have to go home now, have a nice weekend all!
Very interresting to read some discussion.
To all experts: BCB is NOT VC++, gcc,....

Right code is:
//---------------------------------------------------------------------------
#include <vcl\condefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <algorithm>
#include <locale>
#include <iostream>


#pragma hdrstop
//---------------------------------------------------------------------------
USERES("Project1.res");
//---------------------------------------------------------------------------
using namespace std;

char myupper(char c) { return char(toupper(c)); }

int main(int argc, char* argv[])
{
std::string mystring("hello WORLD");
std::transform(mystring.begin(), mystring.end(), mystring.begin(),
myupper);

return 0;
}
AlexVirochovsky,
The method you posted is the method the questioner already stated was his/her current work around.

If you read the questioner's first comment, you'll see the method posted.

Please consider posting your answer as a comment, in the future.  Especially after other experts have already posted solutions or made contributions.
>>The method you posted is the method the questioner already stated was his/her current work around.
I don't see that.
>>From: Axter  Date: 08/10/2001 09:30AM PST  
>>I tried that before. and again it doesn't work.
>>Or, well.  I'm out of ideas.  

Before post my code, I 've tested my code and it works
fine.
Axter, do you have BCB? do you try test code of
barzangy? do you try find way to solve his problem?
I don't see that.
I repete my comment:
>>BCB is NOT VC++, gcc,....

>>Please consider posting your answer as a comment, in the >>future.  Especially after other experts have
>>already posted solutions or made contributions.
We (and especially you) discussed  this theme before ~ month, you can see my rection to this statement.
Good Luck,Alex.


to_upper might be implemented as a macro in BC++

#undef toupper

transform(mystring.begin(), mystring.end(), mystring.begin(), toupper);

I have no way to test this.

-- Dan
AlexVirochovsky, Sorry but you seem not have read all of the postings here. This was already my work arround like Axter said. if you read the earlier postings you'll see the same solution.
DanRollins,
I suggested that method already, and barzangy said it didn't work.
ASKER CERTIFIED SOLUTION
Avatar of Axter
Axter
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Axter, I'm crious about what you'll do, because you found this question fun so I hope I'll get a solution. Thanks
I was answering another question related to this.
The questioner wanted VC++ to use the std::tolower instead of the VC++ tolower.
When he and I tried the following, it didn't compile:
transform(s.begin(), s.end(), s.begin(), std::tolower);

This proved that VC++ is not useing the std::tolower when the std:: is removed from tolower.
To force VC++ to use the std::tolower function, I had to use the following method.


template<class T>
class ToUpper {
public:
    ToUpper(const std::locale& loc):Loc(loc)
    {
    }
    T operator()(const T& Src) const
    {
         return std::toupper<T>(Src, Loc);
    }
protected:
    const std::locale& Loc;
};

template<class T>
class ToLower {
public:
    ToLower(const std::locale& loc):Loc(loc)
    {
    }
    T operator()(const T& Src) const
    {
         return std::tolower<T>(Src, Loc);
    }
protected:
    const std::locale& Loc;
};

void SomeFunction2(void)
{
    std::string data = "Hello World.  How are you axter.  I'm doing find.";
    std::locale locE("english");
    std::transform(data.begin(),data.end(),data.begin(),ToUpper<char>(locE));

    std::wstring wdata = L"Hello World.  How are you axter.  I'm doing find.";
    std::transform(wdata.begin(),wdata.end(),wdata.begin(),ToLower<wchar_t>(locE));
}

This method was required because unlike VC++ tolower, which only needs one arguement, the std::tolower function needs a two arguements.
The second arguement being std::locale.

The above method should work for both VC++ and Borland C++ builder 5.0.