std::transform with std::use_facet<std::ctype<char> >(std::locale()).toupper()

std::transform with std::use_facet<std::ctype<char> >(std::locale()).toupper()

Post by Paul » Thu, 14 Dec 2006 01:50:50


This works all right:
---------------------
#include <string>
#include <algorithm>
#include <cctype>

std::string s("something");
std::transform(s.begin(), s.end(), s.begin(), std::toupper);
---------------------
(other than a compiler warning about assigning int to char -
std::toupper()'s return value is int)

A locale-based replacement for std::toupper - and the one operating on
char's rather than int's - is std::use_facet<std::ctype<char>
>(std::locale()).toupper() as in this example:
---------------------
for (std::string::iterator p = s.begin(); p != s.end(); ++p)
*p = std::use_facet<std::ctype<char> >(std::locale()).toupper(*p);

---------------------
which I tried to incorporate into std::transform() as in the first example
but could not make it. Can this be done?

Also, both

int main(int argc, char* argv[]);

and

VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);

take non-constant arguments (char* and LPTSTR*, respectively). Is this all
right to use the above routine to convert them to upper case? Obviously, I
am not altering them in any other way and do not "extend" them - just
perform upper-case conversion. I know it works and have so far had no
problems but just in case.

Thank you.

Paul
 
 
 

std::transform with std::use_facet<std::ctype<char> >(std::locale()).toupper()

Post by Tom Widmer » Thu, 14 Dec 2006 02:49:20


That won't compile if you #include <locale> (since then toupper is
overloaded). In addition, it has undefined behaviour if s has any
negative characters in it (the domain of toupper is 0-UCHAR_MAX and EOF).


I'd pull the facet creation out of the loop. e.g.
std::ctype<char> const& ct =
std::use_facet<std::ctype<char> >(std::locale());
for (std::string::iterator p = s.begin(); p != s.end(); ++p)
*p = ct.toupper(*p);


//need target type since toupper is overloaded.
char (std::ctype<char>::*fptr)(char) const = &std::ctype<char>::toupper;
std::transform(
s.begin(),
s.end(),
s.begin(),
std::bind1st(
std::mem_fun(fptr),
&std::use_facet<std::ctype<char> >(std::locale())
)
);

However, it may well run slower than the loop, if it fails to inline the
member function calls. It's also less clear than the loop. Finally,
there is also a non-member function in <locale>
char toupper(char, std::locale const&); //actually, it's templated IIRC

However, I'd generally avoid these machinations and instead use the
boost string library: http://www.yqcomputer.com/


I think so.

Obviously, I

It is explicitly defined as legal to modify the argv strings in the C
standard, though the C++ standard doesn't say anything about whether you
can modify them.

Tom

 
 
 

std::transform with std::use_facet<std::ctype<char> >(std::locale()).toupper()

Post by Paul » Thu, 14 Dec 2006 21:22:58

Thank you, Tom.