Re: std::transform with std::use_facet<std::ctype<char> >(std::locale()).toupper()
Paul wrote:
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)
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).
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 = .toupper(*p);
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);
---------------------
which I tried to incorporate into std::transform() as in the first example
but could not make it. Can this be done?
//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.boost.org/doc/html/string_algo.html
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?
I think so.
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.
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