Solved

uppercase transformation

Posted on 2001-08-10
39
740 Views
Last Modified: 2007-12-19
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;
}
0
Comment
Question by:barzangy
  • 18
  • 15
  • 2
  • +3
39 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
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)
0
 

Author Comment

by:barzangy
Comment Utility
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);

0
 
LVL 2

Expert Comment

by:LoungeLizard
Comment Utility
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.
0
 
LVL 2

Expert Comment

by:LoungeLizard
Comment Utility
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!
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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
0
 

Author Comment

by:barzangy
Comment Utility
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;
}
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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);
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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);
0
 

Author Comment

by:barzangy
Comment Utility
Is this L a c++ standard format or just a borland c++ builder extension? where is it documented?
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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.
0
 

Author Comment

by:barzangy
Comment Utility
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);






0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
You could also try the following:

#ifdef _toupper
#undef _toupper
#endif
transform(s.begin(), s.end(), s.begin(), toupper);
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
If my last posted code compiles, then that should be portable.
0
 

Author Comment

by:barzangy
Comment Utility
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.

 
0
 

Author Comment

by:barzangy
Comment Utility
_toupper is not defined in bcb 5.0
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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.
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>_toupper is not defined in bcb 5.0
What was the ctype.h file that you posted?
0
 

Author Comment

by:barzangy
Comment Utility
>>_toupper is not defined in bcb 5.0

So the #ifdef above has no effect.
0
 

Author Comment

by:barzangy
Comment Utility
It was from borland bcb 5.0, but because __STDC__ is defined at that moment. so the _toupper is not defined.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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.
0
 

Author Comment

by:barzangy
Comment Utility
Ok
0
 

Author Comment

by:barzangy
Comment Utility
I tried it just now, no it doesn't work.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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;
}
0
 

Author Comment

by:barzangy
Comment Utility
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)
0
 

Author Comment

by:barzangy
Comment Utility
>>Ok, I have one more idea.
>>Try it without using cctype include.


I tried that before. and again it doesn't work.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>I tried that before. and again it doesn't work.

Oh well.  I'm out of ideas.
0
 

Author Comment

by:barzangy
Comment Utility
I have to go home now, have a nice weekend all!
0
 
LVL 14

Expert Comment

by:AlexVirochovsky
Comment Utility
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;
}
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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.
0
 
LVL 14

Expert Comment

by:AlexVirochovsky
Comment Utility
>>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.


0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
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
0
 

Author Comment

by:barzangy
Comment Utility
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.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
DanRollins,
I suggested that method already, and barzangy said it didn't work.
0
 
LVL 30

Accepted Solution

by:
Axter earned 50 total points
Comment Utility
barzangy,
Unfortunetely, the only computer I have BCB in, is down right now.  I hope to have it up and running Wednesday.
If no one has given you a better answer by then, I'll see what I can come up with.
0
 

Author Comment

by:barzangy
Comment Utility
Axter, I'm crious about what you'll do, because you found this question fun so I hope I'll get a solution. Thanks
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now