473,320 Members | 2,112 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

tolower conflict with iostream?

I get an error when I compile the following code:

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

using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

int
main()
{
string name = "DAVID";

cout << name << " " << lc(name) << endl;
return 0;
}

; g++ lc.cc
lc.cc: In function `std::string& lc(std::string&)':
lc.cc:11: error: no matching function for call to `transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, <unknown type>)'

If I do not include iostream, or if I use a different function
(e.g., int id(int i){return i;}), I do not get any errors. Am I doing
something wrong?

/david

--
Andre, a simple peasant, had only one thing on his mind as he crept
along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
-- unknown
Jul 19 '05 #1
13 5977
In article <3F***************@nomail.com>,
David Rubin <bo***********@nomail.com> wrote:
I get an error when I compile the following code:

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

using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

int
main()
{
string name = "DAVID";

cout << name << " " << lc(name) << endl;
return 0;
}

; g++ lc.cc
lc.cc: In function `std::string& lc(std::string&)':
lc.cc:11: error: no matching function for call to `transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, <unknown type>)'

If I do not include iostream, or if I use a different function
(e.g., int id(int i){return i;}), I do not get any errors. Am I doing
something wrong?


Yes, but you're in good company. This one gets almost everyone at least
once.

There are two kickers (if not more) in this one:

1. tolower is (also) a template function prototyped in <locale>:

template <class charT> charT tolower(charT c, const locale& loc);

2. Any standard C++ header is allowed to include any other standard C++
header as an implementation detail (reference 17.4.4.1/1).

So when you say:

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

and if the templated tolower is in scope, then the compiler can't figure
out what template parameters to try out for tolower<charT>, even if the
non-templated tolower is also in scope. And apparently gcc's <iostream>
brings tolower<charT> into scope as an implementation detail. Thus the
error.

This is a sneaky one in that it may well compile and do what you want
with another compiler. For example it works just fine on Metrowerks,
unless <locale> is explicitly included, and then you get a similar error.

You can correct it, portably, with the following incantation:

transform(s.begin(), s.end(), s.begin(), (int (*)(int))tolower);

I.e. cast tolower to the specific function pointer type that you're
aiming for.

-Howard
Jul 19 '05 #2

"David Rubin" <bo***********@nomail.com> wrote in message
news:3F***************@nomail.com...
I get an error when I compile the following code:

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

using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

int
main()
{
string name = "DAVID";

cout << name << " " << lc(name) << endl;
return 0;
}

; g++ lc.cc
lc.cc: In function `std::string& lc(std::string&)':
lc.cc:11: error: no matching function for call to `transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, <unknown type>)'

If I do not include iostream, or if I use a different function
(e.g., int id(int i){return i;}), I do not get any errors. Am I doing
something wrong?

/david

--
Andre, a simple peasant, had only one thing on his mind as he crept
along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
-- unknown
__________________________________________________ ___________
the way I fixed it is by doing
::tolower
Jul 19 '05 #3
Howard Hinnant <hi*****@metrowerks.com> wrote:
You can correct it, portably, with the following incantation:

transform(s.begin(), s.end(), s.begin(), (int (*)(int))tolower);

I.e. cast tolower to the specific function pointer type that you're
aiming for.


See, even standard library implementers get it wrong :-) This one is,
however, even more subtle: 'std::tolower(int)' can only be called with
values which can be represented by an 'unsigned char' and EOF. However,
on systems where 'char' is a signed entity lots of possible 'char' values,
promoted to 'int', cannot be represented as 'unsigned char'. Although the
above code would be portably compilable, it won't run portably. For a
truely portable solution, you would need an auxiliary function:

char mytolower(char c) {
return std::tolower(static_cast<unsigned char>(c));
}

This will convert the negative 'char' to some positive value first which
stays the same value when converted to 'int'. Promoting a negative 'char'
directly to 'int' and then converting this value to an unsigned type
would yield a value which is [normally (*)] bigger than any value which
can be hold by an 'unsigned char'.

(*): if the number of bits used for 'int' and 'unsigned char' is identical,
it would work...
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>
Jul 19 '05 #4
On Wed, 08 Oct 2003 22:43:22 GMT, Howard Hinnant
<hi*****@metrowerks.com> wrote:
Yes, but you're in good company. This one gets almost everyone at least
once.

There are two kickers (if not more) in this one:

1. tolower is (also) a template function prototyped in <locale>:

template <class charT> charT tolower(charT c, const locale& loc);

2. Any standard C++ header is allowed to include any other standard C++
header as an implementation detail (reference 17.4.4.1/1).

So when you say:

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

and if the templated tolower is in scope, then the compiler can't figure
out what template parameters to try out for tolower<charT>, even if the
non-templated tolower is also in scope.
It's not that clear in the standard that the non-template tolower
shouldn't be chosen. For the templated tolower, argument deduction
would fail, so only the non-template version would be left. In theory
this could be chosen unambiguously.

And apparently gcc's <iostream>brings tolower<charT> into scope as an implementation detail. Thus the
error.

This is a sneaky one in that it may well compile and do what you want
with another compiler. For example it works just fine on Metrowerks,
unless <locale> is explicitly included, and then you get a similar error.
Comeau compiles it fine with both <locale> and <cctype> included.
13.4/2 suggests that it might be ok, but it certainly isn't clear
either way.

http://std.dkuug.dk/jtc1/sc22/wg21/d...ctive.html#115
also has vague relevence.
You can correct it, portably, with the following incantation:

transform(s.begin(), s.end(), s.begin(), (int (*)(int))tolower);

I.e. cast tolower to the specific function pointer type that you're
aiming for.


However, this still has the problem with the domain to tolower being
EOF + the range of unsigned char.

Tom
Jul 19 '05 #5
David Rubin <bo***********@nomail.com> wrote in message news:<3F***************@nomail.com>...
I get an error when I compile the following code:

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

using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

int
main()
{
string name = "DAVID";

cout << name << " " << lc(name) << endl;
return 0;
} /david


david, I don't know that much about c++, but you can do what you want
by flipping the bit in the 32's place. If you know that your string
contains letters, then you can use these 3 functions:

#include <iostream>
#include <string>
using namespace std;

string lcase(string stringin){
string stringout;
for(int i = 0; i < stringin.size(); ++i)
stringout += (stringin[i] | 32);
return stringout;
}

string ucase(string stringin){
string stringout;
for(int i = 0; i < stringin.size(); ++i)
stringout += (stringin[i] & (223));
return stringout;
}

string flipcase(string stringin){
string stringout;
for(int i = 0; i < stringin.size(); ++i)
stringout += (stringin[i] ^ 32);
return stringout;
}

int main(){
cout << "Enter text";
string test;
getline(cin, test);
cout << "Original " << test << endl
<< "All Caps " << ucase(test)<< endl
<< "Lower Case " << lcase(test) << endl
<< "Flip Case " << flipcase(test) << endl;
}

Of course, you will prob. want to clean up the function masks so that
they only effect characters. (eg only effect chars (65 - 90) and (97 -
122)).
Jul 19 '05 #6
"Steven C." <no****@xxx.com> wrote in message news:<KG****************@twister.socal.rr.com>...
"David Rubin" <bo***********@nomail.com> wrote in message
news:3F***************@nomail.com...
I get an error when I compile the following code:

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

using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

int
main()
{
string name = "DAVID";

cout << name << " " << lc(name) << endl;
return 0;
}


I'm sure your aren't interested, but...I improved the functions I just
wrote so that they now ignore all non alphebetic characters. You can
easily change the function to pass a string reference if you want the
change to affect the original string. Anyway...these functions should
work with any string object.

#include <iostream>
#include <string>
using namespace std;

string lcase(string in){
string stringout;
for(int i = 0; i < in.size(); ++i)
if(!(in[i] & 128) & ((in[i] & 95) > 64) & ((in[i] & 31) <= 26))
stringout += (in[i] | 32);
else stringout += in[i]; //character wasn't a letter...dont
change
return stringout;
}

string ucase(string in){
string stringout;
for(int i = 0; i < in.size(); ++i)
if(!(in[i] & 128) & ((in[i] & 95) > 64) & ((in[i] & 31) <= 26))
stringout += (in[i] & (223));
else stringout += in[i]; //character wasn't a letter...dont
change
return stringout;
}

string flipcase(string in){
string stringout;
for(int i = 0; i < in.size(); ++i)
if(!(in[i] & 128) & ((in[i] & 95) > 64) & ((in[i] & 31) <= 26))
stringout += (in[i] ^ 32);
else stringout += in[i]; //character wasn't a letter...dont
change
return stringout;
}

int main(){
cout << "Enter text\n";
string test;
getline(cin, test);
cout << "Original " << test << endl
<< "All Caps " << ucase(test)<< endl
<< "Lower Case " << lcase(test) << endl
<< "Flip Case " << flipcase(test) << endl;
}

in case you are wondering...

if(!(in[i] & 128) & ((in[i] & 95) > 64) & ((in[i] & 31) <= 26))
------------- ------------------ -------------------
0XXX XXXX X10X XXXX 000X XXXX <= 26
000X XXXX > 0
Jul 19 '05 #7
"J. Campbell" wrote:
using namespace std;

string&
lc(string& s)
{
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

[snip] david, I don't know that much about c++, but you can do what you want
by flipping the bit in the 32's place. If you know that your string
contains letters, then you can use these 3 functions:

[snip - code]

Thanks for the code. However, you are assuming an ASCII character set
and a particular locale. The ::tolower solution seems to work well. I
suppose you can extend this to implement Flipcase as a functor (or
simply as a function) using

s[i] = (::isupper(s[i]) ? ::tolower(s[i]) : ::toupper(s[i]));

BTW, for those in the know who are still reading this thread, is* and
to* are known to take an int argument to account for EOF. However, is it
safe to assume that an explicit cast is unnecessary when applying these
functions to a string? Presumably, a string will not contain EOF.

/david

--
Andre, a simple peasant, had only one thing on his mind as he crept
along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
-- unknown
Jul 19 '05 #8
David Rubin wrote:
s[i] = (::isupper(s[i]) ? ::tolower(s[i]) : ::toupper(s[i]));

BTW, for those in the know who are still reading this thread, is* and
to* are known to take an int argument to account for EOF. However, is it
safe to assume that an explicit cast is unnecessary when applying these
functions to a string? Presumably, a string will not contain EOF.


Although the 'is*()' and 'to*()' account for EOF, they do not account
for negative values of 'char' on platforms where 'char' is a signed
entity (at least, they are not required to; I would expect that library
implementers actually do account for this case). Thus, you have to cast
a 'char' to 'unsigned char' before passing them into these functions.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>
Jul 19 '05 #9
Dietmar Kuehl <di***********@yahoo.com> wrote in message news:<bm************@ID-86292.news.uni-berlin.de>...
Although the 'is*()' and 'to*()' account for EOF, they do not account
for negative values of 'char' on platforms where 'char' is a signed
entity (at least, they are not required to; I would expect that library
implementers actually do account for this case). Thus, you have to cast
a 'char' to 'unsigned char' before passing them into these functions.


#include <algorithm>
#include <string>
#include <cctype>

template <int (*F) (int)>
int safe (unsigned char c) { return F(c); }

int main () {
std::string s;
std::transform(s.begin(), s.end(), s.begin(), safe<std::toupper>);
}

As a bonus, this also deals with the overloaded stuff in <locale> --
unless you actually wanted to call those. :)

- Shane
Jul 19 '05 #10
sb******@cs.uic.edu (Shane Beasley) wrote:
template <int (*F) (int)>
int safe (unsigned char c) { return F(c); } [...] std::transform(s.begin(), s.end(), s.begin(), safe<std::toupper>);


That's a nice one! :-)
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>
Jul 19 '05 #11
On 10 Oct 2003 04:29:29 -0700, sb******@cs.uic.edu (Shane Beasley)
wrote:
Dietmar Kuehl <di***********@yahoo.com> wrote in message news:<bm************@ID-86292.news.uni-berlin.de>...
Although the 'is*()' and 'to*()' account for EOF, they do not account
for negative values of 'char' on platforms where 'char' is a signed
entity (at least, they are not required to; I would expect that library
implementers actually do account for this case). Thus, you have to cast
a 'char' to 'unsigned char' before passing them into these functions.


#include <algorithm>
#include <string>
#include <cctype>

template <int (*F) (int)>
int safe (unsigned char c) { return F(c); }


Nice idea, but how about:

#include <string>
#include <functional>

template <int (*F) (int)>
struct safe_to: std::unary_function<char, char>
{
char operator()(char c) const {
return std::char_traits<char>::to_char_type(
F(std::char_traits<char>::to_int_type(c))
);
}
};

With luck, everything will be inlined since safe_to is a functor, and
F is a compile time constant.

Tom
Jul 19 '05 #12
tom_usenet wrote:
#include <string>
#include <functional>

template <int (*F) (int)>
struct safe_to: std::unary_function<char, char>
{
char operator()(char c) const {
return std::char_traits<char>::to_char_type(
F(std::char_traits<char>::to_int_type(c))
I'm not sure what to_int_type does, but you don't want to promote a
negative char value to a negative int value. You want to promote a
negative char value to a non-negative (e.g., unsigned char) value, and
*then* to an int value (implicit in the call to std::tolower).
);
}
};


/david

--
Andre, a simple peasant, had only one thing on his mind as he crept
along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
-- unknown
Jul 19 '05 #13
On Mon, 13 Oct 2003 14:14:53 -0400, David Rubin
<bo***********@nomail.com> wrote:
tom_usenet wrote:
#include <string>
#include <functional>

template <int (*F) (int)>
struct safe_to: std::unary_function<char, char>
{
char operator()(char c) const {
return std::char_traits<char>::to_char_type(
F(std::char_traits<char>::to_int_type(c))


I'm not sure what to_int_type does, but you don't want to promote a
negative char value to a negative int value. You want to promote a
negative char value to a non-negative (e.g., unsigned char) value, and
*then* to an int value (implicit in the call to std::tolower).


to_int_type and to_char_type are for correctly converting between char
and int in the streams sense (e.g. map char to unsigned char values).
It saves on ugly casts (although looks pretty ugly itself). It also
readily converts between wchar_t and wint_t -
char_traits<wchar_t>::to_char_type(mywint);

Tom
Jul 19 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: TheDD | last post by:
Hello, i don't manage to use the tolower() function: #include <algorithm> #include <iostream> #include <locale> #include <string> using std::cout;
2
by: humble04 | last post by:
Hi, I am compiling a collection of C++ code. Most of them are using the new format #include <iostream>. I think all of them because I failed at finding out which header file uses the old format ...
9
by: asbisht | last post by:
Greetings to everyone. #include<iostream> main( void ) { unsigned char value = 'A'; std::cout << tolower(value); return 0; }
4
by: Eric Lilja | last post by:
Hello, consider this program: #include <iostream> #include <algorithm> #include <string> #include <cctype> int main() { std::string s = "HEJ";
3
by: beck2 | last post by:
Hello everyone its Angela again. Can anyone help me please? i want to convert uppercase characters to lower case using the <stdlib.h> and the function tolower. for example i want to display "HELLO"...
5
by: Faray | last post by:
Hello, this is my first post, so hopefully I am posting this in the right place. Hopefully someone will be able to help me out with my problem here it is: I need to make a program that ask a...
6
by: tgnelson85 | last post by:
Hello, I've managed to get my c++ code calling my c code, and i can call a function that prints something to the screen etc. However, i am trying to call the following C function: char*...
1
nurulshidanoni
by: nurulshidanoni | last post by:
Dear all, my algorith is like this while(mor students) read studentID countexam=0 while (more examination) read examcode examID =get ExamID (examCode)
13
by: Soumen | last post by:
I wanted convert a mixed case string to a lower case one. And I tried following code: std::transform(mixedCaseString.begin(), mixedCaseString::end(), mixedCaseString.begin(),...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.