Solved

uppercase transformation

Posted on 2001-08-10
39
750 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
ID: 6372298
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
ID: 6372340
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
ID: 6372369
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
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 
LVL 2

Expert Comment

by:LoungeLizard
ID: 6372392
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
ID: 6372890
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
ID: 6372910
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
ID: 6372970
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
ID: 6372975
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
ID: 6372988
>>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
ID: 6373030
>>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
ID: 6373056
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
ID: 6373083
>>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
ID: 6373089
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
ID: 6373107
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
ID: 6373123
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
ID: 6373128
If my last posted code compiles, then that should be portable.
0
 

Author Comment

by:barzangy
ID: 6373133
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
ID: 6373146
_toupper is not defined in bcb 5.0
0
 
LVL 30

Expert Comment

by:Axter
ID: 6373158
>>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
 
LVL 30

Expert Comment

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

Author Comment

by:barzangy
ID: 6373177
>>_toupper is not defined in bcb 5.0

So the #ifdef above has no effect.
0
 

Author Comment

by:barzangy
ID: 6373184
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
ID: 6373207
>>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
ID: 6373213
Ok
0
 

Author Comment

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

Expert Comment

by:Axter
ID: 6373231
>>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
ID: 6373235
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
ID: 6373241
>>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
ID: 6373252
>>I tried that before. and again it doesn't work.

Oh well.  I'm out of ideas.
0
 

Author Comment

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

Expert Comment

by:AlexVirochovsky
ID: 6375410
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
ID: 6375618
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
ID: 6375658
>>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
ID: 6375987
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
ID: 6377020
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
ID: 6379989
DanRollins,
I suggested that method already, and barzangy said it didn't work.
0
 
LVL 30

Accepted Solution

by:
Axter earned 50 total points
ID: 6380007
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
ID: 6380048
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
ID: 6510153
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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

785 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